Qt GUIで美しい図形を描く:QPainterPath::moveTo()とその他の描画テクニック


QPainterPath::moveTo()は、Qt GUIにおける描画操作において重要な役割を果たす関数です。この関数は、ペインタパスにおける現在の位置を指定された座標へと移動させ、新しいサブパスの開始点を設定します。サブパスとは、線や曲線で構成される、描画パスの連続した部分です。

機能

moveTo()関数には、2つのオーバーロードが存在します。

  1. moveTo(qreal x, qreal y): この関数は、x座標とy座標を個別に指定して、現在の位置を移動させます。
  2. 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:

  1. 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.

  2. 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.

  3. 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



  1. Using QPainter::moveTo()

    The QPainter class also provides a moveTo() function that can be used to set the current drawing position. This function can be particularly useful when drawing directly with the QPainter object, without explicitly creating a QPainterPath. However, it doesn't offer the same level of control over subpaths as QPainterPath::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);
    
  2. Relative Movement with lineTo() and relativeMoveTo()

    Instead of explicitly setting the starting point with moveTo(), you can utilize the lineTo() and relativeMoveTo() 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);
    
  3. Using QPainter::beginPath() and QPainter::endPath()

    If you need to draw multiple paths within a single paintEvent(), you can use QPainter::beginPath() and QPainter::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();
    }