Не могу понять как работает QPainterPath в Qt

140
05 ноября 2021, 06:10

Разбираюсь с рисовкой в Qt, пытаюсь нарисовать свою графическую фигуру, используя QPainterPath. Для этого создаю класс class PuzzlePiece : public QGraphicsPathItem. В нём вся логика по отрисовке. Графический объект будет иметь размеры p_size. Я создаю объект QPainterPath pp;

pp.moveTo(-p_size / 2, -p_size / 2);
pp.lineTo(-p_size / 16, -p_size / 2);
pp.arcTo(-p_size / 8, -p_size / 2 -p_size / 8,
                 p_size / 8, p_size / 8, 270, -90.0);
pp.arcTo(-p_size / 8, -p_size / 2 -p_size / 8 -p_size / 16,
                 p_size / 4, p_size / 4, 180, -180.0);
pp.arcTo(0, -p_size / 2 -p_size / 8,
                 p_size / 8, p_size / 8, 0, -90.0);
pp.lineTo(p_size / 2, -p_size / 2);

На этом этапе отрисовывается лишь часть фигуры (только 3 дуги окружности). Однако, при добавлении ещё одной строки pp.lineTo(p_size / 2, p_size / 2); добавляется оставшаяся часть (две горизонтальные линии). Выглядит это как-то так: Подскажите пожалуйста, почему отрисовка происходит невсегда и от чего это зависит? Спасибо.

Полный код puzzlepiece.cpp:

    #include "puzzlepiece.h"
    #include <QPainter>
    #include <QDebug>
    PuzzlePiece::PuzzlePiece(ConnectorPosition north, ConnectorPosition east,
                             ConnectorPosition south, ConnectorPosition west){
        sides[0] = north;
        sides[1] = east;
        sides[2] = south;
        sides[3] = west;
        ppix = QPixmap("C:/Users/Public/Pictures/Sample Pictures/Хризантема.jpg");
        p_size = 200;
        QPainterPath pp;
        constructPP(pp);
        setPath(pp);
    }
    //void PuzzlePiece::constructShape(QPainterPath &pp){
    //    pp.moveTo(-p_size / 2, -p_size / 2);
    //    switch(sides[0]){
    //        case None:
    //           pp.lineTo(p_size / 2, -p_size / 2);
    //           break;
    //        case Out:
    //            pp.lineTo(-p_size / 16, -p_size / 2);
    //            pp.arcTo(-p_size / 8, -p_size / 2 -p_size / 8,
    //                     p_size / 8, p_size / 8, 270, -90.0);
    //            pp.arcTo(-p_size / 8, -p_size / 2 -p_size / 8 -p_size / 16,
    //                     p_size / 4, p_size / 4, 180, -180.0);
    //            pp.arcTo(0, -p_size / 2 -p_size / 8,
    //                     p_size / 8, p_size / 8, 0, -90.0);
    //            pp.lineTo(p_size / 2, -p_size / 2);
    //            break;
    //        case In:
    //            pp.lineTo(-p_size / 16, -p_size / 2);
    //            pp.arcTo(-p_size / 8, -p_size / 2,
    //                     p_size / 8, p_size / 8, 90, 90.0);
    //            pp.arcTo(-p_size / 8, -p_size / 2 -p_size / 16,
    //                     p_size / 4, p_size / 4, 180, 180.0);
    //            pp.arcTo(0, -p_size / 2,
    //                     p_size / 8, p_size / 8, 0, 90.0);
    //            pp.lineTo(p_size / 2, -p_size / 2);
    //            break;
    //    }
    //    switch(sides[1]){
    //        case None:
    //           pp.lineTo(p_size / 2, p_size / 2);
    //           break;
    //        case Out:
    //            pp.lineTo(p_size / 2 , -p_size / 16);
    //            pp.arcTo(p_size / 2, -p_size / 8,
    //                     p_size / 8, p_size / 8, 180, -90.0);
    //            pp.arcTo(p_size / 2 -p_size / 16, -p_size / 8,
    //                     p_size / 4, p_size / 4, 90, -180.0);
    //            pp.arcTo(p_size / 2, 0,
    //                     p_size / 8, p_size / 8, 270, -90.0);
    //            pp.lineTo(p_size / 2, p_size / 2);
    //            break;
    //        case In:
    //            pp.lineTo(p_size / 2 , -p_size / 16);
    //            pp.arcTo(p_size / 2 -p_size / 8, -p_size / 8,
    //                     p_size / 8, p_size / 8, 0, 90.0);
    //            pp.arcTo(p_size / 2 -p_size / 8 -p_size / 16, -p_size / 8,
    //                     p_size / 4, p_size / 4, 90, 180.0);
    //            pp.arcTo(p_size / 2 -p_size / 8, 0,
    //                     p_size / 8, p_size / 8, 270, 90.0);
    //            pp.lineTo(p_size / 2, p_size / 2);
    //            break;
    //    }
    //    switch(sides[2]){
    //        case None:
    //           pp.lineTo(-p_size / 2, p_size / 2);
    //           break;
    //        case Out:
    //            pp.lineTo(p_size / 16, p_size / 2);
    //            pp.arcTo(0, p_size / 2,
    //                     p_size / 8, p_size / 8, 90, -90.0);
    //            pp.arcTo(-p_size / 8, p_size / 2 -p_size / 16,
    //                     p_size / 4, p_size / 4, 0, -180.0);
    //            pp.arcTo(-p_size / 8, p_size / 2,
    //                     p_size / 8, p_size / 8, 180, -90.0);
    //            pp.lineTo(-p_size / 2, p_size / 2);
    //            break;
    //        case In:
    //            pp.lineTo(p_size / 16, p_size / 2);
    //            pp.arcTo(0, p_size / 2 -p_size / 8,
    //                     p_size / 8, p_size / 8, 270, 90.0);
    //            pp.arcTo(-p_size / 8, p_size / 2 -p_size / 8 -p_size / 16,
    //                     p_size / 4, p_size / 4, 0, 180.0);
    //            pp.arcTo(-p_size / 8, p_size / 2 -p_size / 8,
    //                     p_size / 8, p_size / 8, 180, 90.0);
    //            pp.lineTo(-p_size / 2, p_size / 2);
    //            break;
    //    }
    //    switch(sides[3]){
    //        case None:
    //           pp.lineTo(-p_size / 2, -p_size / 2);
    //           break;
    //        case Out:
    //            pp.lineTo(-p_size / 2 , p_size / 16);
    //            pp.arcTo(-p_size / 2 -p_size / 8, 0,
    //                     p_size / 8, p_size / 8, 0, -90.0);
    //            pp.arcTo(-p_size / 2 -p_size / 8 -p_size / 16, -p_size / 8,
    //                     p_size / 4, p_size / 4, 270, -180.0);
    //            pp.arcTo(-p_size / 2 -p_size / 8, -p_size / 8,
    //                     p_size / 8, p_size / 8, 90, -90.0);
    //            pp.lineTo(-p_size / 2, -p_size / 2);
    //            break;
    //        case In:
    //            pp.lineTo(-p_size / 2 , p_size / 16);
    //            pp.arcTo(-p_size / 2, 0,
    //                     p_size / 8, p_size / 8, 180, 90.0);
    //            pp.arcTo(-p_size / 2 -p_size / 16, -p_size / 8,
    //                     p_size / 4, p_size / 4, 270, 180.0);
    //            pp.arcTo(-p_size / 2, -p_size / 8,
    //                     p_size / 8, p_size / 8, 90, 90);
    //            pp.lineTo(-p_size / 2, -p_size / 2);
    //            break;
    //    }
    //}
    void PuzzlePiece::constructPP(QPainterPath &pp){
        pp.moveTo(-p_size / 2, -p_size / 2);
        pp.lineTo(-p_size / 16, -p_size / 2);
        pp.arcTo(-p_size / 8, -p_size / 2 -p_size / 8,
                         p_size / 8, p_size / 8, 270, -90.0);
        pp.arcTo(-p_size / 8, -p_size / 2 -p_size / 8 -p_size / 16,
                         p_size / 4, p_size / 4, 180, -180.0);
        pp.arcTo(0, -p_size / 2 -p_size / 8,
                         p_size / 8, p_size / 8, 0, -90.0);
        pp.lineTo(p_size / 2, -p_size / 2);
        pp.lineTo(p_size / 2, p_size / 2);
    }
    void PuzzlePiece::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget){
        painter->setClipPath(path());
        painter->setPen(QPen(Qt::black, 3));
        QRect b_rect = boundingRect().toRect();
        painter->drawPixmap(b_rect.x(), b_rect.y(), pixmap());
        painter->drawPath(path());
    }
    QPixmap PuzzlePiece::pixmap(){
        return ppix;
    }
    void PuzzlePiece::setPixmap(QPixmap &pix){
        ppix = pix;
        update();
    }

Полный код puzzlepiece.h:

 #ifndef PUZZLEPIECE_H
    #define PUZZLEPIECE_H
    #include <QGraphicsPathItem>

    class PuzzlePiece : public QGraphicsPathItem
    {
    public:
        enum ConnectorPosition {None, Out, In};
        PuzzlePiece(ConnectorPosition, ConnectorPosition, ConnectorPosition, ConnectorPosition);
        QPixmap pixmap();
        void setPixmap(QPixmap &);
    private:
        int p_size;
        QPixmap ppix;
        ConnectorPosition sides[4];
        void constructPP(QPainterPath &pp);
        void constructShape(QPainterPath &);
        void paint(QPainter *painter,
                  const QStyleOptionGraphicsItem *option,
                  QWidget *widget = nullptr);
    };
    #endif // PUZZLEPIECE_H

main.cpp:

#include <QApplication>
#include "configurationdialog.h"
#include <QDebug>
#include <QGraphicsView>
#include "puzzlepiece.h"
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    QGraphicsView view;
    QGraphicsScene scene;
    scene.addItem(new PuzzlePiece(PuzzlePiece::In, PuzzlePiece::Out,
                                  PuzzlePiece::In, PuzzlePiece::Out));
    view.setScene(&scene);
    view.show();
//    ConfigurationDialog c;
//    c.show();
    return a.exec();
}
Answer 1

Код помог, у вас ошибка в методе отрисовки.

painter->setClipPath(path());
painter->setPen(QPen(Qt::black, 3));
...
painter->drawPath(path());

Первым действием отрисовки вы ограничиваете область отрисовки контуром пазла и только потом отрисовываете этот контур с толщиной линии 3. По факту получается, что, поскольку у линии толщина 3 пикселя вы видите лишь часть своего контура. Когда вы добавляете строку с отрисовкой вертикальной линии, то изменяется общий размер контура и вы видите те части, которые не видно было раньше.

Правильная отрисовка будет выглядеть так:

void PuzzlePiece::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
    painter->setPen(QPen(Qt::black, 3));
    painter->drawPath(path());
    painter->setClipPath(path());
    QRect b_rect = boundingRect().toRect();
    painter->drawPixmap(b_rect.x(), b_rect.y(), pixmap());
}

сначала рисуем контур, потом ставим огранчиение по контуру и рисуем туда пиксмап. Пробуйте)

P.S. попробуйте включить опцию антиалиасинга для пэинтера, отрисовка будет на такой пиксельно

painter->setRenderHint(QPainter::Antialiasing);

READ ALSO
Замена цикла на стандартный алгоритм

Замена цикла на стандартный алгоритм

Можно ли заменить следующий цикл на какой-то стандартный алгоритм библиотеки?

199
Input email неправильно проходит проверку JS Jquery

Input email неправильно проходит проверку JS Jquery

Написал проверку для input-ов на наличие хотя бы 1-ого символа для того чтобы удалить атрибут disabled с кнопки отправкиВ условии так же указал если...

206
метод sort() в JS

метод sort() в JS

Почему на консоль выводится

101
Mожете помочь конвертировать этот js код в pascal

Mожете помочь конвертировать этот js код в pascal

Вы не указали диалект паскаля! Вот решения для паскаля из стандарта ISO 7185:

348