C++ Qt:QWidget::paintEngine:不应再被调用
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/25781353/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Qt: QWidget::paintEngine: Should no longer be called
提问by PH-zero
I'm trying to make an app where you can draw with your finger on a canvas.
To achieve this, I'm subclassing QWidget
as MFCanvas
, registered the class in QML withqmlRegisterType<>()
, implementing the virtual paintEvent();
function, and
drawing on it with a QPainter
inside the paintEvent();
function.
The Problem:
Upon construction, the QPainter
throws this warning:
我正在尝试制作一个应用程序,您可以在其中用手指在画布上绘画。
为了实现这一点,我将QWidget
as子类化MFCanvas
,在 QML 中使用 注册类qmlRegisterType<>()
,实现虚paintEvent();
函数,并在函数内部
绘制它。
问题:
在构建时,抛出此警告:QPainter
paintEvent();
QPainter
QWidget::paintEngine: Should no longer be called
QWidget::paintEngine: 不应再被调用
Then, serveral other related warnings are thrown:
然后,抛出几个其他相关警告:
QPainter::begin: Paint device returned engine == 0, type: 1
QPainter::setPen: Painter not active
No wonder: the QPainter
didn't draw anything...
Also, am i supposed to call paintEvent();
by myself?
Or should it be called every frame by QWidget
, and i somehow messed it up?
I searched the web, but all posts i found had either no answer to them, or they where
using something else than QWidget
.
My Code:
mfcanvas.cpp:
难怪:QPainter
什么都没画……
还有,我应该自己打电话paintEvent();
吗?
还是应该每帧都调用它QWidget
,而我却以某种方式把它搞砸了?
我在网上搜索,但我发现的所有帖子都没有答案,或者他们
使用的不是QWidget
.
我的代码:
mfcanvas.cpp:
#include "mfcanvas.h"
#include <QDebug>
#include <QPainter>
#include <QVector2D>
#include <QList>
MFCanvas::MFCanvas(QWidget *parent) : QWidget(parent)
{
paths = new QList<QList<QVector2D>*>();
current = NULL;
QWidget::resize(100, 100);
}
MFCanvas::~MFCanvas()
{
delete paths;
}
void MFCanvas::paintEvent(QPaintEvent *)
{
if(current!=NULL){
if(current->length() > 1){
QPainter painter(this);
painter.setPen(Qt::black);
for(int i = 1; i < current->length(); i++){
painter.drawLine(current->at(i-1).x(), current->at(i-1).y(), current->at(i).x(), current->at(i).y());
}
}
}
}
void MFCanvas::pressed(float x, float y)
{
if(current==NULL){
qDebug() << "null:"<<current;
current = new QList<QVector2D>();
current->append(QVector2D(x, y));
}else{
qDebug() << "current:"<<current;
}
paintEvent(NULL);
}
void MFCanvas::update(float x, float y)
{
current->append(QVector2D(x, y));
}
void MFCanvas::resize(int w, int h)
{
QWidget::resize(w, h);
}
main.cpp:
主.cpp:
#include <QApplication>
#include <QQmlApplicationEngine>
#include <QtQml>
#include <QSurfaceFormat>
#include "creator.h"
#include "mfcanvas.h"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
qmlRegisterType<MFCanvas>("com.cpp.mfcanvas", 1, 0, "MFCanvas");
QQmlApplicationEngine engine;
QQmlComponent *component = new QQmlComponent(&engine);
QObject::connect(&engine, SIGNAL(quit()), QCoreApplication::instance(), SLOT(quit()));
Creator creator(component);
QObject::connect(component, SIGNAL(statusChanged(QQmlComponent::Status)), &creator, SLOT(create(QQmlComponent::Status)));
component->loadUrl(QUrl("qrc:///main.qml"));
int rv;
rv = app.exec();
delete component;
return rv;
}
creator.cpp:
创建者.cpp:
#include "creator.h"
#include <QQuickWindow>
#include <QDebug>
Creator::Creator(QQmlComponent *component)
{
this->component = component;
}
void Creator::create(QQmlComponent::Status status)
{
if(status == QQmlComponent::Ready){
QObject *topLevel = component->create();
QQuickWindow::setDefaultAlphaBuffer(true);
QQuickWindow *window = qobject_cast<QQuickWindow *>(topLevel);
QSurfaceFormat surfaceFormat = window->requestedFormat();
window->setFormat(surfaceFormat);
window->show();
}
}
main.qml: (the important part)
main.qml:(重要部分)
import QtQuick 2.2
import QtQuick.Controls 1.1
import QtQuick.Controls.Styles 1.2
import QtQuick.Layouts 1.1
import QtQuick.Window 2.0
import com.cpp.mfcanvas 1.0
ApplicationWindow {
visible: true
width: 640
height: 480
title: qsTr("MFCanvas")
onSceneGraphInitialized: {
drawMenu.visible = true;
lineWidth.visible = true;
colorMenu.visible = true;
drawMenu.visible = false;
lineWidth.visible = false;
colorMenu.visible = false;
}
Rectangle {
id: main
anchors.fill: parent
property real toolsH: 15
property real iconW: 25
property real menuH: 8
property real menuW: 16
property real dpi: (Screen.logicalPixelDensity == undefined ? 6 : Screen.logicalPixelDensity) * 1.5
property color choosenColor: Qt.hsla(hue.value, saturation.value, luminance.value, 1)
Text {
anchors.centerIn: parent
font.pointSize: 60
text: "MFCanvas"
}
MFCanvas {
id: canvas
Component.onCompleted: {
canvas.resize(main.width, main.height);
}
}
//...
}
}
Tell me if you need any additional information.
Thank you in advance! =)
如果您需要任何其他信息,请告诉我。
先感谢您!=)
采纳答案by PH-zero
I have found a simple solution myself:
Instead of deriving from QWidget, derive from QQuickPaintedItem. QQuickPaintedItem is a class that was made exactly for what i need: Painting on a QML-Element using a QPainter. Here is the Code (Narrowed down to the essential part):
mfcanvas.h:
我自己找到了一个简单的解决方案:
不是从 QWidget 派生,而是从 QQuickPaintedItem 派生。QQuickPaintedItem 是一个完全满足我需要的类:使用 QPainter 在 QML 元素上绘画。这是代码(缩小到基本部分):
mfcanvas.h:
class MFCanvas : public QQuickPaintedItem
{
Q_OBJECT
public:
explicit MFCanvas(QQuickItem *parent = 0);
~MFCanvas();
protected:
void paint(QPainter *painter);
mfcanvas.cpp:
mfcanvas.cpp:
void MFCanvas::paint(QPainter *painter)
{
painter->translate(-translation.x(), -translation.y());
//...
}
As you can see, a simple paint() function is provided which hands over a pointer to a QPainter, ready to use. =)
如您所见,提供了一个简单的paint() 函数,该函数将一个指向QPainter 的指针移交给准备使用。=)
回答by anonymous
This is nicely explained here:
这在这里得到了很好的解释:
https://forum.qt.io/topic/64693
https://forum.qt.io/topic/64693
In short: do not try to paint from the input event handler directly, but overload the paintEvent method in your widget instead and create the QPainter there. Use the input event exclusively to modify the internal data model and use QPainter in paintEvent to display it, on the output path.
简而言之:不要尝试直接从输入事件处理程序中绘制,而是重载小部件中的paintEvent 方法并在那里创建QPainter。专门使用输入事件来修改内部数据模型,并在paintEvent中使用QPainter来显示它,在输出路径上。
回答by viddik13
In your mfcanvas.cpp, void MFCanvas::pressed(float x, float y)
function, the line
在您的 mfcanvas.cppvoid MFCanvas::pressed(float x, float y)
函数中,该行
paintEvent(NULL);
seems to be disturbing. Tried it in a similar code - I get the same error.
似乎令人不安。在类似的代码中尝试过 - 我得到了同样的错误。
Proposed solution:using this->repaint()
or this->update()
instead of paintEvent(NULL)
to repaint a widget seems to be more appropriate.
建议的解决方案:使用this->repaint()
或this->update()
代替paintEvent(NULL)
重绘小部件似乎更合适。
Possible explanation:looks like paintEvent()shouldn't be called this straightforward (like paintEvent()is called when paint()function is called). As far as I understand from the QPainter doc, the QPainter works together with the QPaintDevice and the QPaintEngine, these three form the basis for painting. The error QWidget::paintEngine: Should no longer be called
puts it quite straight. The lines
可能的解释:看起来像的paintEvent()不应该叫这个简单的(像的paintEvent()时被调用paint()方法调用函数)。据我从 QPainter 文档中了解到,QPainter 与 QPaintDevice 和 QPaintEngine 一起工作,这三个构成了绘画的基础。错误QWidget::paintEngine: Should no longer be called
说得很直。线条
QPainter::begin: Paint device returned engine == 0, type: 1
QPainter::setPen: Painter not active
probably indicate that there's no QPaintEngine provided by this painter's QPaintDevice (like QPaintDevice::paintEngine
). One can assume that this QPaintEngine is generated or otherwise called to existence by the paint device itself, for example, when the paint()function is called on a widget.
可能表明此画家的 QPaintDevice 没有提供 QPaintEngine(如QPaintDevice::paintEngine
)。可以假设这个 QPaintEngine 是由绘画设备本身生成或以其他方式调用存在的,例如,当在小部件上调用paint()函数时。