Reputation: 15736
I'm trying to draw a line (and some other primitives) on a QWidget. That QWidget is physically "on top of" another widget with a picture in it. I want to draw lines and circles over a picture.
I know how to draw a line already. I can do that with this code:
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;
}
But what I really want to do is position a widget to hold a picture, then position a widget over it to hold the lines. Like this:
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);
}
Then to draw the lines and primitives, I want to do it like 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;
}
But this doesn't work. Nothing is drawn. Blank.
The problem is the line that reads QPainter painter(drawnElements);
If I say QPainter painter(this);
, it draws something, but it's not on the child widget, it's on the parent widget.
Upvotes: 1
Views: 1128
Reputation: 98465
The problem is the line that reads
QPainter painter(drawnElements);
Of course. You need to be watching the target widget instead and catch its paint event. To control the order of drawing, you should explicitly deliver the event to the target as well.
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);
}
Feel free to also consider using an overlay widget.
Upvotes: 0
Reputation: 49309
The documentation is pretty clear on the subject:
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.
You should only draw on a widget from its paint event, and you should only draw on that particular widget.
Upvotes: 1