如何在子部件而不是父部件上画一条线?

How to draw a line on a child widget instead of the parent widget?

我正在尝试在 QWidget 上画一条线(和一些其他图元)。该 QWidget 实际上是 "on top of" 另一个带有图片的小部件。我想在图片上画线和圆圈。

我已经会画线了。我可以用这段代码做到这一点:

bool MySpecialWidget::eventFilter( QObject* watched, QEvent* event )
{
    if (watched == this && event->type() == QEvent::Paint)
    {
        QPainter painter(this);

        painter.translate(50, 50);

        painter.setPen(QPen(Qt::blue, 12));
        painter.setBrush(Qt::BrushStyle::SolidPattern);
        painter.drawLine(0, 0, 200, 200);
    }

    return false;
}

但我真正想做的是放置一个小部件来放置图片,然后在其上放置一个小部件来放置线条。像这样:

MySpecialWidget::MySpecialWidget(QWidget *parent) : QWidget(parent)
{
    QRect position = QRect(30, 50, 600, 600);

    pictureBox = new QLabel(parent);
    pictureBox->setGeometry(position);
    pictureBox->setPixmap(QPixmap(QString::fromUtf8(":/main/graphics/MyPicture.png")));
    pictureBox->setScaledContents(true);

    drawnElements = new QWidget(parent);
    drawnElements->setGeometry(position);
    drawnElements->raise();

    this->installEventFilter(this);
}

然后绘制线条和基元,我想这样做:

bool MySpecialWidget::eventFilter( QObject* watched, QEvent* event )
{
    if (watched == this && event->type() == QEvent::Paint)
    {
        QPainter painter(drawnElements);

        painter.translate(50, 50);

        painter.setPen(QPen(Qt::blue, 12));
        painter.setBrush(Qt::BrushStyle::SolidPattern);
        painter.drawLine(0, 0, 200, 200);
    }

    return false;
}

但这不起作用。什么都没有画。空白。

问题出在 QPainter painter(drawnElements);

这行

如果我说 QPainter painter(this);,它会绘制一些东西,但它不在子控件上,而是在父控件上。

关于这个主题的文档非常清楚:

Each widget performs all painting operations from within its paintEvent() function. This is called whenever the widget needs to be redrawn, either as a result of some external change or when requested by the application.

您应该只在其绘制事件中绘制一个小部件,并且您应该只在那个特定的小部件上绘制。

The problem is the line that reads QPainter painter(drawnElements);

当然可以。您需要改为观看 target 小部件并捕获其绘制事件。要控制绘图的顺序,您也应该显式地将事件传递给目标。

bool MySpecialWidget::eventFilter( QObject* watched, QEvent* event )
{
    //         *** vvvvvvvvvvvvv *** (A)
    if (watched == drawnElements && event->type() == QEvent::Paint)
    {
        // Let the target draw itself first.
        watched->event(event);
        // Then overlay our content on it.
        //           *** vvvvvvvvvvvvv *** (B) - must match (A)!
        QPainter painter(drawnElements);
        painter.translate(50, 50);
        painter.setPen(QPen(Qt::blue, 12));
        painter.setBrush(Qt::BrushStyle::SolidPattern);
        painter.drawLine(0, 0, 200, 200);
        return true; // The event is already handled.
    }
    return false;
}

MySpecialWidget::MySpecialWidget(QWidget *parent) : QWidget(parent)
{
    //...
    drawnElements->installEventFilter(this);
}

您也可以考虑使用 overlay widget