PDA

View Full Version : getting weird QPainter error QPain::begin: Paint device returned engine == 0, type: 3



Hossein
12th October 2015, 15:02
Hello Everyone,
I tried adding two timers to my window one for showing the time that some method is being run, the other displaying some information regarding the same method.
to be more precise, the first timer specifies the elapsed time in the realtime , in the form of "00:00:00:00" (as for day:hour:min:sec) that shows how long a method has been being running.
the other timer, gets the progress information of the such method, meaning how many steps have been passed and how many remains, this kind of stuff .

the first timer interval is set to emit every 1000ms , and the second timer is set to 10 ms.

this is how the code looks like now :



void frmCustomNetwork::Init()
{
InitFunctions();

//set timer
timer = new QTimer(0);
connect(timer,SIGNAL(timeout()),this,SLOT(on_Timer Tick()));
timer->setInterval(1000);


timerfast = new QTimer(this);
connect(timerfast,SIGNAL(timeout()),this,SLOT(on_T imerFastTick()));
timerfast->setInterval(10);

//create a new network object
net = new Network(Layers,Network::TrainMode::Sequential,0);

ui->customPlot->addGraph();
// give the axes some labels:
ui->customPlot->xAxis->setLabel("epochs");
ui->customPlot->yAxis->setLabel("errors");
// set axes ranges, so we see all data:
ui->customPlot->xAxis->setRange(ui->txtXaxisLower->text().toFloat(), ui->txtXaxisUpper->text().toFloat());
ui->customPlot->yAxis->setRange(ui->txtYaxisLower->text().toFloat(), ui->txtYaxisUpper->text().toFloat());

ui->sliderEpoch->setMaximum(ui->txtXaxisUpper->text().toInt());
}

...


void frmCustomNetwork::on_btnTrain_clicked()
{
try
{
if( P.size() == 0 || T.size() == 0)
{
QMessageBox::warning(this,"No Sample for training is set","You need to specify some samples with their respective desired outputs first");
return;
}

elapsedSeconds=0;
timer->start();
timerfast->start();
connect(&watcher,SIGNAL(finished()),this,SLOT(on_ThreadJobF inshed()));
future = QtConcurrent::run(this,&frmCustomNetwork::Rec,ui->chkPlot->isChecked());
watcher.setFuture(future);

}
catch(QException ex)
{
QMessageBox::critical(this,"Exception occured in on_btnTrain_clicked()",ex.what());
}
catch(std::exception ex)
{
QMessageBox::critical(this,"Exception occured in on_btnTrain_clicked()",ex.what());
}
catch(...)
{
QMessageBox::critical(this,"Exception occured on_btnTrain_clicked()","Uknown Exception occured");
}
}

and these are the timers and watchers slot respectively.


void frmCustomNetwork::on_TimerTick()
{
try
{
elapsedSeconds++;

day = elapsedSeconds / (24*3600);
hour = (elapsedSeconds % (24*3600)) / 3600 ;
min = ((elapsedSeconds % (24*3600)) % 3600) / 60;
second = ((elapsedSeconds % (24*3600)) % 3600) % 60;

ui->lblElapsedTime->setText(QString::number(day)+" : "+QString::number(hour)+" : "+QString::number(min)+" : "+QString::number(second));

}
catch(QException ex)
{
QMessageBox::critical(this,"Exception occured in on_btnTrain_clicked()",ex.what());
}
catch(...)
{
QMessageBox::critical(this,"Exception occured in on_btnTrain_clicked()","UnExpected Exception occured! ");
}
}

void frmCustomNetwork::on_TimerFastTick()
{
QString epoch = QString::number(net->GetCurrentEpochNumber());
QString patternIndex = QString::number(net->GetCurrentPatternNumber());

ui->lblCurrentEpoch->setText(epoch);
ui->lblCurrentPattern->setText(patternIndex);

}


void frmCustomNetwork::on_ThreadJobFinshed()
{
timer->stop();
timerfast->stop();
elapsedSeconds = 0;
}


Now when the application runs, everything is just fine, when the method in question ends, the application crashes , and inside QtCreator I can see these error messages:


Starting G:\ProjectsCenter\ArtificialNeuralNetworksProject\ QtProject\ANN\release\Ann.exe...
QPainter::begin: Paint device returned engine == 0, type: 3
QPainter::setCompositionMode: Painter not active
QPainter::end: Painter not active, aborted
The program has unexpectedly finished.
G:\ProjectsCenter\ArtificialNeuralNetworksProject\ QtProject\ANN\release\Ann.exe crashed


Update
For some time it seems to be running just fine, but again it fails unexpectedly : here is another error message that poped up just after executing the method in question successfully for 3 times, (on the forth time this is what I get):

QMetaObject::connectSlotsByName: No matching signal for on_btnLoadCorrectSamples_clicked()
QMetaObject::connectSlotsByName: No matching signal for on_btnLoadWrongSamples_clicked()
QPainter::begin: Paint device returned engine == 0, type: 3
QPainter::setCompositionMode: Painter not active
QPainter::end: Painter not active, aborted
The program has unexpectedly finished.
G:\ProjectsCenter\ArtificialNeuralNetworksProject\ QtProject\ANN\release\Ann.exe crashed
Whats causing it ?

I also tried putting

QCoreApplication::processEvents();
in timer slots, but that doesnt prevent crashes.

anda_skoa
12th October 2015, 16:02
the first timer specifies the elapsed time in the realtime , in the form of "00:00:00:00" (as for day:hour:min:sec) that shows how long a method has been being running.

Just as an improvement: instead of incrementing a counter, start a QElapsedTimer when you start being interested in elapsed time and use its elapsed time counting.
The QTimer is then only used for getting the current value and updating the UI.

That way your display is always accurate, even if the timer event is delayed, etc.



Now when the application runs, everything is just fine, when the method in question ends, the application crashes , and inside QtCreator I can see these error messages:

What is the method in question?
Where does it crash according to the backtrace?

Cheers,
_

Hossein
12th October 2015, 18:40
Just as an improvement: instead of incrementing a counter, start a QElapsedTimer when you start being interested in elapsed time and use its elapsed time counting.
The QTimer is then only used for getting the current value and updating the UI.

That way your display is always accurate, even if the timer event is delayed, etc.


What is the method in question?
Where does it crash according to the backtrace?

Cheers,
_
OK , Ill change that to QElapsedTimer,
for the method in question , here it is :


bool frmCustomNetwork::Rec(bool plot)
{

if(!InitNetwork())
return false;

auto errorVect = net->Train(false);
errorVector.clear();
errorVector = QVector<double>::fromStdVector(errorVect) ;
if (plot)
{
epochRange.clear();
for(int i =0; i < errorVector.size(); i++)
epochRange.push_back(i);

InitGraphSettings(errorVect);

ui->customPlot->graph(0)->setData(epochRange,errorVector );
ui->customPlot->replot();

}

if(ui->chkdislayErrors->isChecked())
{
ui->txtInfo->setText(QString::number(errorVector.size()));
for(int i =0; i < errorVector.size(); i++)
ui->txtInfo->append(QString::number(errorVector[i]) );
}
return true;
}

which calls these :


bool frmCustomNetwork::InitNetwork()
{
if(Layers.size()==0)
{
QMessageBox::critical(this,"No Layer is set","No Layer is added, please add some layers first");
return false;
}

bool output =false,hidden=false;
for(auto &l:Layers)
{
if ( l->GetType() == Layer::LayerType::Output)
output = true;
else if ( l->GetType() == Layer::LayerType::Hidden)
hidden = true;
}

if (!(output && hidden))
{
QMessageBox::critical(this,"Not enough layers are set","You must alteast have one or more hidden layers and only one output layer");
return false;
}

Network::TrainMode mode;
int count=0;
Layers[0]->SetAsFirstLayer(true);

while (count < Layers.size())
{
Layer* layer = Layers[count];
if (layer->GetType() != Layer::LayerType::Output)
{
Layer* layer2 = Layers[count+1];
layer->ConnectToLayer(layer2,true);
}
count++;
}

if(ui->rdBtnSeq->isChecked())
mode = Network::TrainMode::Sequential;
else
mode = Network::TrainMode::Batch;



net->SetLayers(Layers);
net->SetMode(mode);
net->SetEpoch(ui->txtEpoch->text().toInt());
net->SetLearningRate(ui->txtLearningRate->text().toFloat());
net->SetInputs(P);
net->SetTargets(T);
net->SetErrorVectorStatus(ui->chkErrorsSquared->isChecked());


return true;
}

void frmCustomNetwork::InitGraphSettings( vector<double>& res)
{
auto result = std::minmax_element(res.begin(), res.end());
double errorMin = *result.first;//min
double errorMax = *result.second;//max
ui->txtYaxisLower->setText(QString::number(errorMin));
ui->txtYaxisUpper->setText(QString::number(errorMax));

ui->sliderEpoch->setValue(ui->txtEpoch->text().toInt());
on_sliderEpoch_sliderMoved( ui->sliderEpoch->value());
}


Added after 1:

I guess I found out what the cause is. I guess its because of the spawned thread trying to access and modify the UI components. When I commented the plot section, the crashes stopped.
I need to investigate much further though to make sure this is the casue.
In the meantime , if this is the case, How should I solve this ?
Thanks in advacne

anda_skoa
12th October 2015, 18:54
Only the main thread (the thread that created QApplication instance and runs QApplication::exec()) can access UI components.

If you have a thread that generates data that needs to be displayed, you have various methods at your disposal.
The easiest one is usually to emit a signal with the data and connect it to a slot of an object running in the main thread.

Cheers,
_

Hossein
12th October 2015, 20:12
Only the main thread (the thread that created QApplication instance and runs QApplication::exec()) can access UI components.

If you have a thread that generates data that needs to be displayed, you have various methods at your disposal.
The easiest one is usually to emit a signal with the data and connect it to a slot of an object running in the main thread.

Cheers,
_
I'm lost here, I would greatly appreciate a sample demonstrating what you are suggesting.

ChrisW67
12th October 2015, 22:06
How are you handling cancellation and cleanup of the the QFuture object and its associated background thread if the program is terminated?

Hossein
13th October 2015, 04:12
How are you handling cancellation and cleanup of the the QFuture object and its associated background thread if the program is terminated?

Do I have to clean QFuture ? ! Isn't the background thread itself terminated when it finishes its job?

Hossein
13th October 2015, 07:47
Ok, I managed to create a thread but I get an errror message saying :


QObject::connect: Cannot queue arguments of type 'std::vector<double>'
(Make sure 'std::vector<double>' is registered using qRegisterMetaType().)

This is how I used the thread:

void frmCustomNetwork::on_btnTrain_clicked()
{
try
{
if( P.size() == 0 || T.size() == 0)
{
QMessageBox::warning(this,"No Sample for training is set","You need to specify some samples with their respective desired outputs first");
return;
}

if(!InitNetwork())
return ;

timer->start();
timerfast->start();

trainThread = new TrainInThread(net);
connect(trainThread,SIGNAL(processDone(std::vector<double>)),this,SLOT(OnTrainingFinished(std::vector<double>)));
trainThread.start();
}
catch(QException ex)
{
QMessageBox::critical(this,"Exception occured in on_btnTrain_clicked()",ex.what());
}
catch(std::exception ex)
{
QMessageBox::critical(this,"Exception occured in on_btnTrain_clicked()",ex.what());
}
catch(...)
{
QMessageBox::critical(this,"Exception occured on_btnTrain_clicked()","Uknown Exception occured");
}
}

void frmCustomNetwork::OnTrainingFinished(std::vector<double> errorVect)
{
timer->stop();
timerfast->stop();

errorVector.clear();
errorVector = QVector<double>::fromStdVector(errorVect);

if (ui->chkPlot->isChecked())
{
epochRange.clear();
for(int i =0; i < errorVector.size(); i++)
epochRange.push_back(i);

InitGraphSettings(errorVect);

ui->customPlot->graph(0)->setData(epochRange,errorVector );
ui->customPlot->replot();

}

if(ui->chkdislayErrors->isChecked())
{
ui->txtInfo->setText(QString::number(errorVector.size()));
for(int i =0; i < errorVector.size(); i++)
ui->txtInfo->append(QString::number(errorVector[i]) );
}
}


Here is my implementation of QThread :

#ifndef TRAININGINTHREAD
#define TRAININGINTHREAD
#include <QThread>
#include <QString>

class Network;

class TrainInThread :
public QThread
{
Q_OBJECT //Don't forget this MACRO to let this class emit SIGNALS

public:
TrainInThread(Network* net,bool showTrace =false );
~TrainInThread();
void run();

signals:
void processDone(std::vector<double>);//SIGNAL to show that some process have been done

private:
Network* _net;
bool _showTrace;

};
#endif // TRAININGINTHREAD




#include "../../ArtificialNeuralNetworksProject/Network.h"
#include "traininginthread.h"
#include <QDebug>
TrainInThread::TrainInThread(Network* net, bool showTrace):_showTrace(showTrace)
{
_net = net;
}

TrainInThread::~TrainInThread()
{}

void TrainInThread::run()
{
//Do heavy process
auto errorVect = _net->Train(_showTrace);
//Emit a SIGNAL with the error vector
emit processDone(errorVect);
}

Whats wrong with this code?
I got the idea from here (http://www.qtcentre.org/threads/32416-Update-GUI-from-another-thread)and here (http://www.qtcentre.org/threads/32416-Update-GUI-from-another-thread)

Added after 1 13 minutes:

found the cause, I had to place this inside the TrainingInThread's constructor

qRegisterMetaType< std::vector<double> >( "std::vector<double>" );//for signal to be able to send std::vector<double>

Hossein
13th October 2015, 10:41
By the way how can i terminate an existing thread?
when I do
if(trainThread && trainThread->isRunning())
trainThread->exit();

it just gives me an exception 0xc0000005, which accessing a nullpointer usually !
I am doing this before I create new threads, (suppose user clicks on the same button twice, and while the previous thread is still running, a new one is spawned and the a crash happens here, I am trying to prevent this in fact.
So how should I go about this one?

anda_skoa
13th October 2015, 14:06
QThread::exit() ends the thread's event loop, your thread does not run an event loop.
It will exit as soon as its run() method returns.

There is no save way to "end" a thread without its cooperation.

Cheers,
_

Hossein
13th October 2015, 17:58
QThread::exit() ends the thread's event loop, your thread does not run an event loop.
It will exit as soon as its run() method returns.

There is no save way to "end" a thread without its cooperation.

Cheers,
_

Thanks, so how can I do that ?
do you mean incorporating an event loop inside the Train() method ?
Isn't there any break method that would ungracefully kill a thread! :-/

anda_skoa
13th October 2015, 19:23
do you mean incorporating an event loop inside the Train() method ?

If you don't need event processing then just checking a stop flag would be sufficient.



Isn't there any break method that would ungracefully kill a thread! :-/

You can terminate a thread, but then your application is in an unknown state.
It could crash, deadlock, leak memory, etc., because it all depends on what the thread was doing, which resources it held and so on when it was terminated.

Hence "no save way" of doing it other then asking the thread to stop doing what it is doing. Or rather build exit points into whatever code is being executed, because there you know about those things.

If you don't have control over what the thread's "payload" code is doing, then you could consider running it in a separate process.
Unless the code uses some system global resources (e.g. explicit file locks, system semaphores), it can be safely terminated by the operating system.

Cheers,
_