Qt paintEvent crashes - c++

Im trying to draw simple board on my widget.
When I'm trying to automatize this, my paintEvent crashes. I think it is caused by for loop inside, am I right? How to paint it in other way?
void Widget::paintEvent(QPaintEvent *event)
{
QPixmap myPix( QSize(20,20) );
QPainter painter(this);
for(int i = 0; i < 100; i+5){
painter.drawLine(QPointF(i,0),QPointF(i,max));
}
this->setPixmap(myPix);
}

Your for loop is incorrect and causes the program crash (I'm sure that's not your fault here). It should be written like this:
for(int i = 0; i < 100; i+=5){
p.drawLine(QPointF(i,0),QPointF(i,max));
}
i.e. with an assignment of the increment. This way it will do the job and finish properly.
On a side note, I would suggest to use drawPixmap() instead of setPixmap(). But setPixmap() will not cause infinite recursion and for example next code works properly.
//...
this->setPixmap(QPixmap("G:/2/qt.jpg"));
QLabel::paintEvent(event);
Why? With this approach infinite recursion is never produced (see here):
If you call repaint() in a function which may itself be called from
paintEvent(), you may get infinite recursion. The update() function
never causes recursion.
Indeed setPixmap() calls update(), not repaint(). To prove that see source code:
setPixmap source:
void QLabel::setPixmap(const QPixmap &pixmap)
{
Q_D(QLabel);
//...
d->updateLabel();//what it does?
}
updateLabel source:
void QLabelPrivate::updateLabel()
{
Q_Q(QLabel);
//...
q->updateGeometry();
q->update(q->contentsRect());//not repaint
}
As I said it is not a mistake but I think that it will be better if you will do all what you need with QPainter.

Related

qt5 QGraphicsScene setBackgroundBrush() not always work when called frequently

I want to write an tool of objective annotation using qt5 MinGw32, which could annotate object in video file and diplay them during playing. So QGraphicsScene is inherited to implementation the function.
Something wrong happens when I change the QGraphicsScene's background frequently(e.g. 30 fps): most of time it works as expected while sometimes the background could not move.
Here is my code:
void MyGraphicsScene::UpdateFrame(QImage image)
{
QPixmap pixmap = QPixmap::fromImage(image);
//fix the view's size and scene's size
views().first()->setFixedSize(pixmap.size());
setSceneRect(0,0, pixmap.width(), pixmap.height());
setBackgroundBrush(QBrush(pixmap));
}
...
//In another thread
void Thread::run()
{
...
myScene.UpdateFrame(newImage);
...
}
I have search through the qt's document and found no answer.
However, there is something strange:
when wrong thing happens, I find the background continues to change, but it didn't show change on the screen unless I move the app to another screen (I have two screen). However, with the app moved, the QGraphicsScene's background just change once and becomes static afterwards.
I guess the background has been changed but doesn't repainted, so I used update(), but it didn't help.
BTW, I couldn't reproduce the occasion, sometiems it happens, somtimes not.
do I need to represented any methods? Or I called the methods in a wrong way? Or is there an alternative approach that would work?
Many thanks for your help in advance.
You should not change QtGui elements from a different thread by calling a method directly.
Use the Qt signal-slot concept.
Calling update() is not necessary.
class MyGraphicsScene{...
....
signals:
void singalFromThread(QImage image);
public:
//CTor
MyGraphicsScene()
{
connect(this, SIGNAL(singalFromThread(QImage)),this,SLOT(UpdateFrame(QImage)));
}
//Call this method from your thread
void updateForwarder(QImage image)
{
//Jump into gui thread
emit singalFromThread(image);
}
public slots:
void UpdateFrame(QImage image)
{
setBackgroundBrush(....);
}
};

How to add an effect on QGraphicsView?

I'm trying to add a blur effect on my graphicsView but i have to trigger the action twice to apply the effect.The first time i trigger it, it applies the effect on the graphicsView's borderline and on the second trigger it applies it on the scene.Here is my code(the same with colorize effect):
void MainWindow::on_actionBlur_triggered()
{
QGraphicsBlurEffect *a=new QGraphicsBlurEffect;
a->setBlurHints(QGraphicsBlurEffect::QualityHint);
a->boundingRectFor(ui->graphicsView->viewport()->rect());
ui->graphicsView->setGraphicsEffect(a);
}
Can you spot the mistake or propose a different way fo doing this?
I've find a solution by calling the trigger for a second recursively.In numOfTriggers i save the times that i called it.
void Editor::on_actionBlur_triggered()
{
if(numOfTriggers<2){
QGraphicsBlurEffect *a=new QGraphicsBlurEffect;
a->setBlurHints(QGraphicsBlurEffect::QualityHint);
a->boundingRectFor(ui->graphicsView->viewport()->rect());
ui->graphicsView->setGraphicsEffect(a);
numOfTriggers++;
on_actionBlur_triggered();
}
else{
numOfTriggers=0;
}
}
I have another idea : you should pass the QGraphicsView to your QGraphicsBlurEffect in constructor.
QGraphicsBlurEffect* a = new QGraphicsBlurEffect(ui->graphicsView);
Give a try with your mainWindow or "this" if not working.

Qt application crashes after call to removeItem() in QGrahicsScene

I'm facing a problem I cannot explain yet. In the "Designer" GUI there is a QGraphicsView which I use as a placeholder for a custom GraphicsView. I have overridden the resizeEvent() method there and set the scene's rect.
The scene which is a custom class, too I'd like to use to display a graph.
The problem: Sometimes when starting the application it crashes and sometimes it doesn't. This behavior does not follow a rule, i.e. sometimes I start it ten times before crashing sometimes three times and so on.
I took a screenshot of the call stack but seems like I am not capable of understanding the problem. Hope someone of you does.
First things first, here is the code:
mainwindow.cpp
graph = new GraphScene(this);
ui->gv_graph->setScene(graph);
graph->addAxisLabels("P", "t");
graphicsview.cpp
GraphicsView::GraphicsView(QWidget *parent)
:QGraphicsView(parent)
{
}
void GraphicsView::resizeEvent(QResizeEvent *event)
{
if(GraphScene *s = dynamic_cast<GraphScene*>(scene()))
s->updateSceneRect(QRectF(QPointF(0,0), event->size()));
}
graphscene.cpp
const float GraphScene::margin = 20.0f;
GraphScene::GraphScene(QObject *parent)
:QGraphicsScene(parent)
{
}
void GraphScene::updateSceneRect(const QRectF &rect)
{
setSceneRect(rect);
if(_frameRect)
removeItem(_frameRect);
_frameRect = new QGraphicsRectItem;
_frame.setTopLeft(QPointF(margin, margin));
_frame.setWidth(rect.width()-2*margin);
_frame.setHeight(rect.height()-2*margin);
_frameRect->setRect(_frame);
addItem(_frameRect);
}
void GraphScene::addAxisLabels(const QString& xLabel, const QString& yLabel)
{
if(_xLabel)
removeItem(_xLabel);
if(_yLabel)
removeItem(_yLabel);
_xLabel = new QGraphicsSimpleTextItem(xLabel);
_xLabel->setX(margin+1);
_xLabel->setY(margin+1);
addItem(_xLabel);
//_yLabel = new QGraphicsSimpleTextItem;
}
So as what I see from the call stack the problem occurs when calling removeItem() in one of the both functions above.
The screenshot:
Environment information:
Can someone provide some help, hints or whatever. This would be very much appreciated. Thank you!

what wxYield() returns? Is it related to why my guauge is not updated?

I am using wxwidgets and I have a code like this:
gaugeProgressFolders->SetRange(folderList.size());
for(int i=0;i<folderList.size();i++)
{
ProcessOneSet(folderList[i]);
gaugeProgressFolders->SetValue(i+1);
wxYield();
}
The wxYeild doesn't update guauge. I am wondering why it is not working?
Looking at wxYield, I noted that it returns a bool but there is no documentation on what it returns.
Why my guauge is not update and how I can fix it?
what wxYield returns?
You do not say what gaugeProgressFolders is. Perhaps it is wxGauge?
In any case, why do you expect wxYield to magically update the display?
You have to write code to update the display.
Assuming various things about your code, you could write something like this:
gaugeProgressFolders->SetRange(folderList.size());
for(int i=0;i<folderList.size();i++)
{
ProcessOneSet(folderList[i]);
gaugeProgressFolders->SetValue(i+1);
// wxYield(); Don't call this, it does nothing
// force the window to be repainted RIGHT NOW.
Refresh();
Update();
}
You might also try the following, for the sake of efficency and less flicker
// force the gauge to be repainted.
gaugeProgressFolders->Refresh();
gaugeProgressFolders->Update();
Perhaps this is a little late to respond, but I don't think wxYield() is the right call for your purpose of updating a gauge. Perhaps try:
gaugeProgressFolders->SetRange(folderList.size());
for (int i = 0; i < folderList.size(); i++)
{
ProcessOneSet(folderList[i]);
gaugeProgressFolders->SetValue(i+1);
this->Layout(); //this being your window/dialog/frame
}
Layout() forces the layout to redraw. It has been effective for me in the past.

Draw pixel based graphics to a QWidget

I have an application which needs to draw on a pixel by pixel basis at a specified frame rate (simulating an old machine). One caveat is that the main machine engine runs in a background thread in order to ensure that the UI remains responsive and usable during simulation.
Currently, I am toying with using something like this:
class QVideo : public QWidget {
public:
QVideo(QWidget *parent, Qt::WindowFlags f) : QWidget(parent, f), screen_image_(256, 240, QImage::Format_RGB32) {
}
void draw_frame(void *data) {
// render data into screen_image_
}
void start_frame() {
// do any pre-rendering prep work that needs to be done before
// each frame
}
void end_frame() {
update(); // force a paint event
}
void paintEvent(QPaintEvent *) {
QPainter p(this);
p.drawImage(rect(), screen_image_, screen_image_.rect());
}
QImage screen_image_;
};
This is mostly effective, and surprisingly not very slow. However, there is an issue. The update function schedules a paintEvent, it may not hapen right away. In fact, a bunch of paintEvent's may get "combined" according to the Qt documentation.
The negative effect that I am seeing is that after a few minutes of simulation, the screen stops updating (image appears frozen though simulation is still running) until I do something that forces a screen update for example switching the window in and out of maximized.
I have experimented with using QTimer's and other similar mechanism to have the effect of the rendering being in the GUI thread so that I can force immediate updates, but this resulted in unacceptable performance issues.
Is there a better way to draw pixels onto a widget constantly at a fixed interval. Pure Qt solutions are preferred.
EDIT: Since some people choose to have an attitude instead of reading the whole question, I will clarify the issue. I cannot use QWidget::repaint because it has a limitation in that it must be called from the same thread as the event loop. Otherwise, no update occurs and instead I get qDebug messages such as these:
QPixmap: It is not safe to use pixmaps outside the GUI thread
QPixmap: It is not safe to use pixmaps outside the GUI thread
QWidget::repaint: Recursive repaint detected
QPainter::begin: A paint device can only be painted by one painter at a time.
QWidget::repaint: It is dangerous to leave painters active on a widget outside of the PaintEvent
QWidget::repaint: It is dangerous to leave painters active on a widget outside of the PaintEvent
EDIT: to demonstrate the issue I have created this simple example code:
QVideo.h
#include <QWidget>
#include <QPainter>
class QVideo : public QWidget {
Q_OBJECT;
public:
QVideo(QWidget *parent = 0, Qt::WindowFlags f = 0) : QWidget(parent, f), screen_image_(256, 240, QImage::Format_RGB32) {
}
void draw_frame(void *data) {
// render data into screen_image_
// I am using fill here, but in the real thing I am rendering
// on a pixel by pixel basis
screen_image_.fill(rand());
}
void start_frame() {
// do any pre-rendering prep work that needs to be done before
// each frame
}
void end_frame() {
//update(); // force a paint event
repaint();
}
void paintEvent(QPaintEvent *) {
QPainter p(this);
p.drawImage(rect(), screen_image_, screen_image_.rect());
}
QImage screen_image_;
};
main.cc:
#include <QApplication>
#include <QThread>
#include <cstdio>
#include "QVideo.h"
struct Thread : public QThread {
Thread(QVideo *v) : v_(v) {
}
void run() {
while(1) {
v_->start_frame();
v_->draw_frame(0); // contents doesn't matter for this example
v_->end_frame();
QThread::sleep(1);
}
}
QVideo *v_;
};
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
QVideo w;
w.show();
Thread t(&w);
t.start();
return app.exec();
}
I am definitely willing to explore options which don't use a temporary QImage to render. It is just the only class in Qt which seems to have a direct pixel writing interface.
Try emitting a signal from the thread to a slot in the event loop widget that calls repaint(), which will then execute right away. I am doing something like this in my graphing program, which executes the main calculations in one thread, then tells the widget when it is time to repaint() the data.
In similar cases what I did was still using a QTimer, but doing several simulation steps instead of just one. You can even make the program auto-tuning the number of simulation steps to be able to get whatever frames per seconds you like for the screen update.