Hy everyone, I'm a beginner at QT and c++ and I wanted to see how to use a QPainter and events in Qt but I got stuck because of an error message during the execution, my original code:
Hy大家好,我是QT和c++的初学者,我想看看如何在QT中使用QPainter和事件,但是在执行过程中我遇到了错误消息,我的原始代码:
the main.cpp
的main.cpp
#include "customwidget.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QScopedPointer<QWidget> widget(new customWidget());
widget->resize(240, 120);
widget->show();
return a.exec();
}
and the header:
标题:
#ifndef CUSTOMWIDGET_H
#define CUSTOMWIDGET_H
#include <QWidget>
#include <QMouseEvent>
#include <QPoint>
#include <QPainter>
class customWidget : public QWidget
{
Q_OBJECT
public:
explicit customWidget(QWidget *parent = 0);
void paintEvent(QPaintEvent *);
void mouseMoveEvent(QMouseEvent *event);
void mousePressEvent(QMouseEvent *event);
private:
QPoint m_mousePos;
QRect m_r2;
signals:
void needToRepaint();
public slots:
};
#endif // CUSTOMWIDGET_H
and the .cpp:
. cpp:
#include "customwidget.h"
customWidget::customWidget(QWidget *parent) : QWidget(parent)
{
QRect m_r2;
QPoint m_mousePos;
QObject::connect(this, SIGNAL(needToRepaint()), this, SLOT(repaint()));
}
void customWidget::paintEvent(QPaintEvent *)
{
QPainter painter(this);
// ############ First Rectangle ****************************************
QRect r1 = rect().adjusted(10, 10, -10, -10);
painter.setPen(QColor("#FFFFFF"));
painter.drawRect(r1);
// ############ Seconde Rectangle ****************************************
QRect r2(QPoint(0, 0), QSize(100, 100));
m_r2.moveCenter(m_mousePos);
QPainter painter2;
QPen pen;
painter2.setPen(QColor("#000000"));
pen.setWidth(3);
painter2.setPen(pen);
painter2.drawRect(m_r2);
update();
}
void customWidget::mouseMoveEvent(QMouseEvent *event)
{
m_mousePos = event->pos();
emit needToRepaint();
}
I tried to search it on the web and saw that it's because the QPainter isn't located in the paintEvent but it's not the case in my code, thanks for your help.
我试着在网上搜索它,发现它是因为QPainter不在paintEvent中,但在我的代码中不是这样的,谢谢你的帮助。
1 个解决方案
#1
1
-
You only need one painter. The second one wasn't activated, and you don't need it anyway.
你只需要一个画家。第二个没有被激活,你也不需要它。
-
Don't ever call
repaint()
unless you somehow absolutely need the painting to be done beforerepaint()
returns (that's what happens!). If you keep the event loop running properly, you won't ever need that.不要调用repaint(),除非在repaint()返回之前必须完成这幅画()。如果让事件循环正常运行,就永远不需要它。
-
Don't call
update()
frompaintEvent()
: it's nonsense (literally).不要从paintEvent()中调用update():它是无意义的。
-
When you wish to repaint the widget, call
update()
: it schedules an update from the event loop. Multiple outstanding updates are coalesced to keep the event loop functional and prevent event storms.当您希望重新绘制小部件时,调用update():它从事件循环调度更新。多个未完成的更新被合并,以保持事件循环的功能和防止事件风暴。
-
Let the compiler generate even more memory management code for you. You've done the first step by using smart pointers - that's good. Now do the second one: hold the instance of
CustomWidget
by value. It doesn't have to be explicitly dynamically allocated. C++ is not C, you can leverage values.让编译器为您生成更多的内存管理代码。你已经用智能指针完成了第一步——这很好。现在执行第二个操作:按值保存CustomWidget的实例。它不需要显式地动态分配。c++不是C,你可以利用值。
-
In a simple test case, you don't want three files. Your code should fit in as few lines as possible, in a single
main.cpp
. If you need to moc the file due toQ_OBJECT
macros, add#include "main.moc"
at the end, and re-run qmake on the project to take notice of it.在一个简单的测试用例中,您不需要三个文件。您的代码应该在一个main.cpp中尽可能少地包含几行代码。如果由于Q_OBJECT宏需要moc文件,请添加#include“main”。moc“在最后,重新运行qmake对项目进行关注。
This is how such a test case should look, after fixing the problems. Remember: it's a test case, not a 100kLOC project. You don't need nor want the meager 35 lines of code spread across three files. Moreover, by spreading out the code you're making it harder for yourself to comprehend.
在修复问题之后,这样的测试用例应该是这样的。记住:这是一个测试用例,而不是一个100kLOC项目。您不需要也不希望这35行代码分散在三个文件中。此外,通过扩展代码,您将使自己更难理解。
Even in big projects, unless you can show significant build time improvements if doing the contrary, you can have plenty of small classes implemented Java-style completely in the header files. That's about the only Java-style-anything that belongs in C++.
即使是在大型项目中,除非您能够在相反的情况下显示显著的构建时间改进,否则您可以在头文件中拥有大量实现java风格的小类。这是c++中惟一的java风格——任何属于它的东西。
// https://github.com/KubaO/*n/tree/master/questions/simple-paint-38796140
#include <QtWidgets>
class CustomWidget : public QWidget
{
QPoint m_mousePos;
public:
explicit CustomWidget(QWidget *parent = nullptr) : QWidget{parent} {}
void paintEvent(QPaintEvent *) override;
void mouseMoveEvent(QMouseEvent *event) override {
m_mousePos = event->pos();
update();
}
};
void CustomWidget::paintEvent(QPaintEvent *)
{
QPainter painter(this);
auto r1 = rect().adjusted(10, 10, -10, -10);
painter.setPen(Qt::white);
painter.drawRect(r1);
auto r2 = QRect{QPoint(0, 0), QSize(100, 100)};
r2.moveCenter(m_mousePos);
painter.setPen(QPen{Qt::black, 3, Qt::SolidLine, Qt::SquareCap, Qt::MiterJoin});
painter.drawRect(r2);
}
int main(int argc, char ** argv) {
QApplication app{argc, argv};
CustomWidget w;
w.show();
return app.exec();
}
#1
1
-
You only need one painter. The second one wasn't activated, and you don't need it anyway.
你只需要一个画家。第二个没有被激活,你也不需要它。
-
Don't ever call
repaint()
unless you somehow absolutely need the painting to be done beforerepaint()
returns (that's what happens!). If you keep the event loop running properly, you won't ever need that.不要调用repaint(),除非在repaint()返回之前必须完成这幅画()。如果让事件循环正常运行,就永远不需要它。
-
Don't call
update()
frompaintEvent()
: it's nonsense (literally).不要从paintEvent()中调用update():它是无意义的。
-
When you wish to repaint the widget, call
update()
: it schedules an update from the event loop. Multiple outstanding updates are coalesced to keep the event loop functional and prevent event storms.当您希望重新绘制小部件时,调用update():它从事件循环调度更新。多个未完成的更新被合并,以保持事件循环的功能和防止事件风暴。
-
Let the compiler generate even more memory management code for you. You've done the first step by using smart pointers - that's good. Now do the second one: hold the instance of
CustomWidget
by value. It doesn't have to be explicitly dynamically allocated. C++ is not C, you can leverage values.让编译器为您生成更多的内存管理代码。你已经用智能指针完成了第一步——这很好。现在执行第二个操作:按值保存CustomWidget的实例。它不需要显式地动态分配。c++不是C,你可以利用值。
-
In a simple test case, you don't want three files. Your code should fit in as few lines as possible, in a single
main.cpp
. If you need to moc the file due toQ_OBJECT
macros, add#include "main.moc"
at the end, and re-run qmake on the project to take notice of it.在一个简单的测试用例中,您不需要三个文件。您的代码应该在一个main.cpp中尽可能少地包含几行代码。如果由于Q_OBJECT宏需要moc文件,请添加#include“main”。moc“在最后,重新运行qmake对项目进行关注。
This is how such a test case should look, after fixing the problems. Remember: it's a test case, not a 100kLOC project. You don't need nor want the meager 35 lines of code spread across three files. Moreover, by spreading out the code you're making it harder for yourself to comprehend.
在修复问题之后,这样的测试用例应该是这样的。记住:这是一个测试用例,而不是一个100kLOC项目。您不需要也不希望这35行代码分散在三个文件中。此外,通过扩展代码,您将使自己更难理解。
Even in big projects, unless you can show significant build time improvements if doing the contrary, you can have plenty of small classes implemented Java-style completely in the header files. That's about the only Java-style-anything that belongs in C++.
即使是在大型项目中,除非您能够在相反的情况下显示显著的构建时间改进,否则您可以在头文件中拥有大量实现java风格的小类。这是c++中惟一的java风格——任何属于它的东西。
// https://github.com/KubaO/*n/tree/master/questions/simple-paint-38796140
#include <QtWidgets>
class CustomWidget : public QWidget
{
QPoint m_mousePos;
public:
explicit CustomWidget(QWidget *parent = nullptr) : QWidget{parent} {}
void paintEvent(QPaintEvent *) override;
void mouseMoveEvent(QMouseEvent *event) override {
m_mousePos = event->pos();
update();
}
};
void CustomWidget::paintEvent(QPaintEvent *)
{
QPainter painter(this);
auto r1 = rect().adjusted(10, 10, -10, -10);
painter.setPen(Qt::white);
painter.drawRect(r1);
auto r2 = QRect{QPoint(0, 0), QSize(100, 100)};
r2.moveCenter(m_mousePos);
painter.setPen(QPen{Qt::black, 3, Qt::SolidLine, Qt::SquareCap, Qt::MiterJoin});
painter.drawRect(r2);
}
int main(int argc, char ** argv) {
QApplication app{argc, argv};
CustomWidget w;
w.show();
return app.exec();
}