PDA

View Full Version : QPaintEngine::setSystemClip: Should not be changed...



jiveaxe
8th August 2007, 14:42
Hi, I have a problem with my new sample application; I was reading QTextDocument manual and as exercise I wrote an application very simple:

- a textEdit where insert html code
- a button for passing the textEdit->text() to...
- a widget that reimplement paintEvent() so it uses textDocument->setHtml() to render text.

Application compiles right (even if I not wrote the connection); but during execution console fills with these two lines:


QPaintEngine::setSystemClip: Should not be changed while engine is active
QPaintEngine::setSystemRect: Should not be changed while engine is active

and the application seems not responding to commands.

Thanks for the help.

Here the code:

viewer.h

#ifndef VIEWER_H
#define VIEWER_H

class QPainter;

class Viewer: public QWidget
{
public:
Viewer(QWidget *parent = 0);

protected:
void paintEvent(QPaintEvent *event);
};

#endif

viewer.cpp

#include <QtGui>

#include "viewer.h"

Viewer::Viewer(QWidget *parent)
: QWidget(parent)
{
setStyleSheet("background-color: white");
}


void Viewer::paintEvent(QPaintEvent * /* event */)
{
QPainter *painter = new QPainter(this);
QTextDocument doc;
doc.setHtml("<strong>What's wrong</strong> with <em>this code?</em>");
QAbstractTextDocumentLayout::PaintContext context;
doc.setPageSize(QSize(250,300));
painter->translate(10, 10);
doc.documentLayout()->draw(painter, context);
}

main.cpp

#include <QtGui>

#include "viewer.h"

int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QWidget *window = new QWidget;
window->setWindowTitle("Painter & QTextDocument");

QLabel *htmlStringLabel = new QLabel("HTML code:");
QTextEdit *htmlTextEdit = new QTextEdit;
htmlTextEdit->setMaximumHeight(150);
htmlTextEdit->setMinimumHeight(150);
QPushButton *drawButton = new QPushButton("&Draw");
Viewer *viewer = new Viewer;
viewer->setMinimumHeight(150);
viewer->setMinimumWidth(100);

QHBoxLayout *labelLayout = new QHBoxLayout;
labelLayout->addWidget(htmlStringLabel);
labelLayout->addStretch();

QHBoxLayout *buttonLayout = new QHBoxLayout;
buttonLayout->addStretch();
buttonLayout->addWidget(drawButton);
buttonLayout->addStretch();

QVBoxLayout *mainLayout = new QVBoxLayout;
mainLayout->addLayout(labelLayout);
mainLayout->addWidget(htmlTextEdit);
mainLayout->addLayout(buttonLayout);
mainLayout->addWidget(viewer);
mainLayout->setMargin(2);
mainLayout->setSpacing(0);

window->setLayout(mainLayout);
window->resize(400,400);
window->show();

return app.exec();
}

marcel
8th August 2007, 15:06
That is because in paintEvent you create a painter on the heap and you don't delete at the end of the function, meaning the paint device(the widget) remains active.
When the next paint event occurs, you get the warning, since a paint was already in progress.

So, call delete painter; at the end of the paint event.

Another thing: it is not a good idea to create a text doc in every paint event.
Instead create it as a member.

Regards

jiveaxe
8th August 2007, 15:13
As usual quick and efficient!
Thank you marcel, delete painter; does the job.

jiveaxe
8th August 2007, 15:28
One more question. Why with my some applications with reimplemented paintEvent() after the paint event the paint area is not updated if not moving the mouse?

Regards

marcel
8th August 2007, 15:32
Well, you'll have to post an example that reproduces that...

Regards

jiveaxe
8th August 2007, 16:48
Here I am
and here a sample code with the problem (only implementation):

viewer.cpp

#include <QtGui>

#include "viewer.h"

Viewer::Viewer(QWidget *parent)
: QWidget(parent)
{
setStyleSheet("background-color: white");
}

void Viewer::paintEvent(QPaintEvent * /* event */)
{
QPainter *painter = new QPainter(this);
doc.setHtml(htmlString);
QAbstractTextDocumentLayout::PaintContext context;
doc.setPageSize(QSize(250,300));
painter->translate(10, 10);
doc.documentLayout()->draw(painter, context);
delete painter;
}

void Viewer::setHtmlString(QString string)
{
htmlString = string;
}


dialog.cpp

#include <QtGui>

#include "dialog.h"

Dialog::Dialog(QWidget *parent)
:QDialog(parent)
{
htmlStringLabel = new QLabel("HTML code:");
htmlTextEdit = new QTextEdit;
htmlTextEdit->setMaximumHeight(150);
htmlTextEdit->setMinimumHeight(150);
drawButton = new QPushButton("&Draw");
viewer = new Viewer;
viewer->setMinimumHeight(150);
viewer->setMinimumWidth(100);

QHBoxLayout *labelLayout = new QHBoxLayout;
labelLayout->addWidget(htmlStringLabel);
labelLayout->addStretch();

QHBoxLayout *buttonLayout = new QHBoxLayout;
buttonLayout->addStretch();
buttonLayout->addWidget(drawButton);
buttonLayout->addStretch();

QVBoxLayout *mainLayout = new QVBoxLayout;
mainLayout->addLayout(labelLayout);
mainLayout->addWidget(htmlTextEdit);
mainLayout->addLayout(buttonLayout);
mainLayout->addWidget(viewer);
mainLayout->setMargin(2);
mainLayout->setSpacing(0);

setLayout(mainLayout);
resize(400,400);

connect(drawButton, SIGNAL(clicked()), this, SLOT(drawHtmlString()));
}

void Dialog::drawHtmlString()
{
viewer->setHtmlString(htmlTextEdit->toPlainText());
}

After pushing the button nothing changes in painting area; only if I move the mouse over it the new text is painted.

Bye

marcel
8th August 2007, 16:54
You need to schedule a viewer repaint by calling its update() merthod.
You can do this either in Dialog::drawHtmlString by calling viewer->update() after setting the html, or in Viewer::setHtmlString, after assigning the new string, by calling update();

Regards

jiveaxe
8th August 2007, 17:06
Again a simple and useful hint by marcel(TM) ;).

Thanks again