Qt GUIで美しい図形を描く:QPainterPath::moveTo()とその他の描画テクニック
QPainterPath::moveTo()
は、Qt GUIにおける描画操作において重要な役割を果たす関数です。この関数は、ペインタパスにおける現在の位置を指定された座標へと移動させ、新しいサブパスの開始点を設定します。サブパスとは、線や曲線で構成される、描画パスの連続した部分です。
機能
moveTo()
関数には、2つのオーバーロードが存在します。
moveTo(qreal x, qreal y)
: この関数は、x座標とy座標を個別に指定して、現在の位置を移動させます。moveTo(const QPointF &point)
: この関数は、QPointF
型のポイントオブジェクトを使用して、現在の位置を移動させます。
どちらの関数も、新しいサブパスの開始点を設定します。既存のサブパスが存在する場合は、そのサブパスは自動的に閉じられます。
例
QPainterPath path;
// 現在の位置を (10, 20) に移動し、新しいサブパスを開始
path.moveTo(10, 20);
// (10, 20) から (50, 30) まで線を描画
path.lineTo(50, 30);
// (50, 30) から (30, 50) まで線を描画
path.lineTo(30, 50);
// (30, 50) から (10, 20) まで線を描画して、サブパスを閉じる
path.lineTo(10, 20);
このコード例では、moveTo()
関数を使用して、四角形の形状を表すサブパスを作成しています。
QPainterPath
クラスは、塗りつぶしや縁取りなどの描画操作にも使用できます。- 複数のサブパスを繋ぎ合わせることで、複雑な形状を描画することができます。
moveTo()
関数は、描画操作の開始点だけでなく、サブパスの開始点も設定するために使用できます。
#include <QApplication>
#include <QWidget>
#include <QPainterPath>
#include <QPainter>
class MyWidget : public QWidget
{
public:
MyWidget(QWidget *parent = nullptr) : QWidget(parent) {}
protected:
void paintEvent(QPaintEvent *event) override
{
QPainter painter(this);
QPainterPath path;
// Start a new subpath at (10, 20)
path.moveTo(10, 20);
// Draw a line to (50, 30)
path.lineTo(50, 30);
// Draw a line to (30, 50)
path.lineTo(30, 50);
// Draw a line back to (10, 20) to close the subpath
path.lineTo(10, 20);
// Fill the path with red
painter.setPen(Qt::red);
painter.fillPath(path);
// Draw the path outline in black
painter.setPen(Qt::black);
painter.drawPath(path);
}
};
int main(int argc, char **argv)
{
QApplication app(argc, argv);
MyWidget widget;
widget.setWindowTitle("Drawing with QPainterPath");
widget.show();
return app.exec();
}
This code will create a simple rectangular shape with a red fill and a black outline. The moveTo()
function is used to specify the starting point of each line segment that makes up the rectangle.
Here is a breakdown of the code:
Include the necessary headers
#include <QApplication> #include <QWidget> #include <QPainterPath> #include <QPainter>
These headers provide the classes and functions that we need to create a widget and draw on it.
Create a MyWidget class
class MyWidget : public QWidget { public: MyWidget(QWidget *parent = nullptr) : QWidget(parent) {} protected: void paintEvent(QPaintEvent *event) override { QPainter painter(this); QPainterPath path; // Start a new subpath at (10, 20) path.moveTo(10, 20); // Draw a line to (50, 30) path.lineTo(50, 30); // Draw a line to (30, 50) path.lineTo(30, 50); // Draw a line back to (10, 20) to close the subpath path.lineTo(10, 20); // Fill the path with red painter.setPen(Qt::red); painter.fillPath(path); // Draw the path outline in black painter.setPen(Qt::black); painter.drawPath(path); } };
This class defines a custom widget that will draw a rectangular shape. The
paintEvent()
method is called whenever the widget needs to be repainted.Implement the paintEvent() method
void paintEvent(QPaintEvent *event) override { QPainter painter(this); QPainterPath path; // Start a new subpath at (10, 20) path.moveTo(10, 20); // Draw a line to (50, 30) path.lineTo(50, 30); // Draw a line to (30, 50) path.lineTo(30, 50); // Draw a line back to (10, 20) to close the subpath path.lineTo(10, 20); // Fill the path with red painter.setPen(Qt::red); painter.fillPath(path); // Draw the path outline in black painter.setPen(Qt::black); painter.drawPath(path); }
This method is responsible for drawing the rectangular shape. The
Using QPainter::moveTo()
The
QPainter
class also provides amoveTo()
function that can be used to set the current drawing position. This function can be particularly useful when drawing directly with theQPainter
object, without explicitly creating aQPainterPath
. However, it doesn't offer the same level of control over subpaths asQPainterPath::moveTo()
.QPainter painter(this); // Set the current drawing position to (10, 20) painter.moveTo(10, 20); // Draw a line to (50, 30) painter.lineTo(50, 30); // Draw a line to (30, 50) painter.lineTo(30, 50); // Draw a line back to (10, 20) to close the subpath painter.lineTo(10, 20); // Fill the path with red painter.setPen(Qt::red); painter.fillPath(path); // Draw the path outline in black painter.setPen(Qt::black); painter.drawPath(path);
Relative Movement with lineTo() and relativeMoveTo()
Instead of explicitly setting the starting point with
moveTo()
, you can utilize thelineTo()
andrelativeMoveTo()
functions to define the path relative to the current position. This approach is particularly useful when constructing paths incrementally.QPainterPath path; // Start the path at the current position (assuming it's (0, 0)) path.lineTo(10, 20); // Draw a line relative to the current position (10, 20) path.lineTo(40, 10); // Draw a line relative to the current position (50, 30) path.lineTo(-20, 20); // Draw a line back to the starting position (10, 20) path.lineTo(-40, -10); // Fill the path with red painter.setPen(Qt::red); painter.fillPath(path); // Draw the path outline in black painter.setPen(Qt::black); painter.drawPath(path);
Using QPainter::beginPath() and QPainter::endPath()
If you need to draw multiple paths within a single
paintEvent()
, you can useQPainter::beginPath()
andQPainter::endPath()
to define individual paths. This approach provides more explicit control over subpaths and their associated drawing operations.void paintEvent(QPaintEvent *event) override { QPainter painter(this); // Draw the first rectangle painter.beginPath(); painter.moveTo(10, 20); painter.lineTo(50, 30); painter.lineTo(30, 50); painter.lineTo(10, 20); painter.setPen(Qt::red); painter.fillPath(); painter.setPen(Qt::black); painter.drawPath(); painter.endPath(); // Draw the second rectangle painter.beginPath(); painter.moveTo(70, 80); painter.lineTo(110, 90); painter.lineTo(90, 110); painter.lineTo(70, 80); painter.setPen(Qt::green); painter.fillPath(); painter.setPen(Qt::black); painter.drawPath(); painter.endPath(); }