Reputation: 21
I am trying to draw a line at the center of a widget, so I tried to call paintEvent()
by using update()
.
However, paintEvent()
does not get called. Why is that?
test_paint.h:
#ifndef TEST_PAINT_H
#define TEST_PAINT_H
#include <QPainter>
#include <QWidget>
class test_paint:public QWidget{
Q_OBJECT
public:
test_paint(QWidget* device){paper = device;}
protected:
void paintEvent(QPaintEvent* e){
QPainter p(paper);
QPen myPen;
myPen.setColor(Qt::red);
myPen.setWidth(5);
p.setPen(myPen);
QPoint p1;
QPoint p2;
p1.setX(10);
p1.setY(10);
p2.setX(100);
p2.setY(10);
p.drawLine(p1,p2);
};
void try_painting(){
update();
}
public slots:
void call_paint(){
try_painting();
}
private:
QWidget* paper;
};
#endif // TEST_PAINT_H
main.cpp:
#include <QApplication>
#include <QPushButton>
#include <QMainWindow>
#include <QMenu>
#include <QMenuBar>
#include <QWidget>
#include <QVBoxLayout>
#include <QObject>
#include "test_paint.h"
int main(int argc, char* argv[]){
QApplication a(argc,argv);
QMainWindow window;
window.setFixedSize(500, 600);
QMenu menu("Menu");
window.menuBar()->addMenu("Menu");
QWidget *center = new QWidget();
window.setCentralWidget(center);
window.show();
QPushButton* push = new QPushButton("test_move");
QVBoxLayout* vlayout = new QVBoxLayout();
vlayout -> addWidget(push);
center->setLayout(vlayout);
test_paint* d = new test_paint(center);
QObject::connect(push,SIGNAL(clicked()),d,SLOT(call_paint()));
return a.exec();
}
Upvotes: 2
Views: 172
Reputation: 2365
You have 3 problems with your approach:
You have this:
QWidget *center = new QWidget();
window.setCentralWidget(center);
window.show();
QPushButton* push = new QPushButton("test_move");
QVBoxLayout* vlayout = new QVBoxLayout();
vlayout -> addWidget(push);
center->setLayout(vlayout);
test_paint* d = new test_paint(center);
Where you initialize d
with center
as its parent, and you do not include it in any layout. And that is after you make window
(center
's parent) visible, which is a problem because a parent widget will only make its children visible if added before it itself is made visible (see my answer on How to make a child widget added in a slot visible?).
To fix that, you could either move the initialization before the parent's show
:
QWidget *center = new QWidget();
window.setCentralWidget(center);
test_paint* d = new test_paint(center);
window.show();
QPushButton* push = new QPushButton("test_move");
QVBoxLayout* vlayout = new QVBoxLayout();
vlayout -> addWidget(push);
center->setLayout(vlayout);
Or, you could call d.show();
.
However, this still won't work:
d
will become a second window.And that is because of the second problem:
You have the below as your constructor:
test_paint(QWidget* device) { paper = device; }
Which does not initialize the base class with the parent widget that you pass as device
, thus not enabling you to benefit from parent/child relations between widgets.
This leads to improper events handling and propagation, and ultimately paintEvent
not getting triggered, or causing a second window, all of which is mentioned in QWidget Documentation:
QWidget *parent = nullptr
is the parent of the new widget. If it isnullptr
(the default), the new widget will be a window. If not, it will be a child of parent, and be constrained by parent's geometry (unless you specify Qt::Window as window flag).
So you fix that as follows:
test_paint(QWidget* device) : QWidget(device) { paper = device; }
base class initialization ->^^^^^^^^^^^^^^^
And again, this will turn up another problem:
In test_paint::paintEvent
, you have this:
QPainter p(paper);
Which means you want to draw/draw in top of paper
, however the current paintEvent
is that of d
, not paper
, that will cause you the following warnings:
QWidget::paintEngine: Should no longer be called
QPainter::begin: Paint device returned engine == 0, type: 1
QPainter::setPen: Painter not active
To fix that, you should use the current widget and draw on it:
QPainter p(this);
Here's a simplified, minimal example:
#include <QApplication>
#include <QtWidgets>
class test_paint : public QWidget
{
public:
test_paint(QWidget* parent) : QWidget(parent) {}
protected:
void paintEvent(QPaintEvent* e) override
{
qDebug()<<"painting"<<size();
QPainter p(this);
p.fillRect(rect(), Qt::white);
}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QWidget w;
test_paint d(&w);
QPushButton push("test");
QVBoxLayout vlayout;
vlayout.addWidget(&push);
w.setLayout(&vlayout);
QObject::connect(&push, &QPushButton::clicked, [&d]()
{
qDebug()<<"updating";
d.update();
});
w.show();
return a.exec();
}
Result:
Some of the output:
painting QSize(100, 30)
painting QSize(100, 30)
painting QSize(100, 30)
updating
painting QSize(100, 30)
painting QSize(100, 30)
painting QSize(100, 30)
updating
painting QSize(100, 30)
painting QSize(100, 30)
painting QSize(100, 30)
Upvotes: 1