我试图在小部件的中心画一条线,所以我尝试使用
paintEvent()
来调用 update()
。
但是,
paintEvent()
不会被调用。这是为什么?
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();
}
您的方法存在 3 个问题:
你有这个:
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);
将
d
初始化为 center
作为其父级,并且不将其包含在任何布局中。那是在您使 window
(center
的父级)可见之后,这是一个问题,因为父级小部件只有在其本身可见之前添加,才会使其子级可见(请参阅如何做上的我的答案)使添加到插槽中的子小部件可见?)。
要解决这个问题,您可以将初始化移到父级的
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);
或者,您可以致电
d.show();
。
但是,这仍然行不通:
d
将成为第二个窗口。这是因为第二个问题:
您有以下内容作为您的构造函数:
test_paint(QWidget* device) { paper = device; }
这不会使用您作为 device
传递的父窗口小部件
初始化基类,因此无法让您从窗口小部件之间的父/子关系中受益。
这会导致不正确的事件处理和传播,并最终导致
paintEvent
不被触发,或导致第二个窗口,所有这些都在QWidget文档中提到:
是新小部件的父级。如果是QWidget *parent = nullptr
(默认),新的小部件将是一个窗口。如果不是,它将是父级的子级,并受到父级几何形状的约束(除非您指定 Qt::Window 作为窗口标志)。nullptr
因此您可以按如下方式修复该问题:
test_paint(QWidget* device) : QWidget(device) { paper = device; }
base class initialization ->^^^^^^^^^^^^^^^
再次,这会出现另一个问题:
在
test_paint::paintEvent
中,你有这个:
QPainter p(paper);
这意味着您想在
paper
之上绘制/绘制,但是当前的paintEvent
是d
而不是paper
,这将导致您出现以下警告:
QWidget::paintEngine: Should no longer be called
QPainter::begin: Paint device returned engine == 0, type: 1
QPainter::setPen: Painter not active
要解决这个问题,您应该使用当前的小部件并在其上绘图:
QPainter p(this);
这是一个简化的、最小的示例:
#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();
}
结果:
一些输出:
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)