Help me understand the QThread usage - qt

I have the MainWindow w windows and TestThread testThread as a member of w. I know it i simple, but I cannot run the testThread.foo() method in testThread thread (not in window thread). In another words: I don't understand the QThread behavior.
Please help correct the next test application. There is a QProgressBar *MainWindow::ui::progressBar and QPushButton *MainWindow::ui::startButton (write simply). I want to start (by startButton click) TestThread::foo(int* progress) which will increment int progress each second.
MainWindow:
MainWindow::MainWindow(QWidget *parent) : // ...
{
// ...
ui->progressBar->setRange(0, 5);
progress = 0; // int MainWindow::progress
this->connect(ui->startButton, SIGNAL(clicked()), SLOT(startFoo()));
connect(this, SIGNAL(startFooSignal(int*)), &testThread, SLOT(foo(int*)));
// TestThread MainWindow::testThread
testThread.start();
}
// ...
void MainWindow::timerEvent(QTimerEvent *event)
{
ui->progressBar->setValue(progress);
}
void MainWindow::startFoo() // this is a MainWindow SLOT
{
startTimer(100);
emit startFooSignal(&progress);
// startFooSignal(int*) is a MainWindows SIGNAL
}
TestThread:
void TestThread::foo(int *progress) // this is a TestThread SLOT
{
for (unsigned i = 0; i < 5; ++i) {
sleep(1);
++*progress; // increment MainWindow::progress
}
}
I know, this is simple. I am doing something wrong :)
P.S. I want to run the simpliest (as possible) example to understand the QThread behavior.
Thanks!

The critical issue is to have the object containing the foo()-function be owned by that thread, so that slot calls are dispatched from the right thread's event-loop.
(Note that there's no need to actually have foo() on the TestThread object. You can use separate objects for QThread and WhatEver::foo() function. It might be easier too, I'm not sure..)
IIUC, this is what you have to do:
Use QObject::moveToThread() to assign the object containing the foo-function to TestThread (that means that Qt::AutoConenction (the default) signal/slots calls will run correctly across thread, being dispatched from each thread's own event loop).
By having the object "owned" by the right thread, slots calls will be scheduled on that thread's event loop, rather than executed directly.
Hope it helps. :)

One alternative solution: If you just want to run a function in another thread, and don't insist using QThread, you should check out the QT Concurrent Namespace.
The following example will run the function foo() in separate thread and will not block on the line where calling the function. Of course there are mechanisms to understand when a function ends, to get a result, to wait for it, to control execution.
void foo(int &progress) {...}
int progress;
QtConcurrent::run(foo, progress);
Hope this helps

See QThread::start and QThread::run.

Related

QT how to restart a thread?

How to properly restart a QThread? I have been googling this four hours and can't find any concrete answer.
What I have is the basic moveToThread implementation:
VideoHandler::VideoHandler()
{
VideoBurner *videoBurner = new VideoBurner;
videoBurner->moveToThread(&videoBurnerThread);
connect(this, &VideoHandler::signalVideoData, videoBurner, &VideoBurner::setVideoData);
connect(this, &VideoHandler::signalVideoBurn, videoBurner, &VideoBurner::initVideoBurn);
// don't really want it since there is only 1 object
//connect(&videoBurnerThread, &QThread::finished, videoBurner, &QObject::deleteLater);
connect(videoBurner, &VideoBurner::burnProcess, this, [=](QString step, int percentage){
emit burningProcess(step, percentage);
});
}
This is the declaration of my Class:
class VideoHandler : public QObject
{
Q_OBJECT
QThread videoBurnerThread;
...
bunch of defintions
...
}
The VideoBurner class is also a subclass of QObject
class VideoBurner : public QObject
{
Q_OBJECT
...
bunch of definitions
...
}
For the first run this works perfect, signals and slots all work.
The issue happens when I want to "cancel" the thread.
For example it is working on some "heavy" calculation that I want to stop from the main thread so I call: videoBurnerThread.quit(); with a cancel function from VideoHandler.
I don't wait() on it as it would block the main thread.
quit() triggers &QThread::finished, but I commented out that connection as it destroys my only object instance.
(also I can't find any example that creates an object and puts it on a thread outside a constructor, if that's even possible? when I tried the app would just close without errors)
I found that the quit() only stops the event loop, not doing anything besides that, which leads to the issue of restarting the tread.
After I want to do the "heavy" stuff again, and I call videoBurnerThread.start(); to start it again, I get results of last performed function from VideoBurner and some signals from it, before it actually starts doing what it should.
Can I somehow stop whatever it was working on and just restart it? I tried sending an "abort" signal from VideoHandler so it doesn't emit signals, but that didn't work.
Do I absolutely need the &QObject::deleteLater so it stops? If so, how to reinitialize VideoBurner correctly inside some function and reconnect it's signal/slot?
Also there is no logic in VideoBurner destructor just a public: virtual ~VideoBurner(){};, could this be an issue?
Call "this->deleteLater()" at the end of your worker.
Connect the worker destroyed signal to the thread quit slot in your Handler function.
Refer to this code snippet.
if(!dataThread.isRunning())
{
worker = new Worker();
dataThread.setObjectName("dataThread");
worker->moveToThread(&dataThread);
QObject::connect(&dataThread, &QThread::started, worker, &Worker::run);
QObject::connect(worker, &Worker::destroyed, &dataThread, &QThread::quit);
QObject::connect(worker, &Worker::set_counter_label, this, &MainWindow::update_counter);
dataThread.start();
}

Qt event loop and unit testing?

I'we started experimenting with unit testing in Qt and would like to hear comments on a scenario that involves unit testing signals and slots.
Here is an example:
The code i would like to test is (m_socket is a pointer to QTcpSocket):
void CommunicationProtocol::connectToCamera()
{
m_socket->connectToHost(m_cameraIp,m_port);
}
Since that is an asynchronous call i can't test a returned value. I would however like to test if the response signal that the socket emits on a successful connection (void connected ()) is in fact emitted.
I've written the test below:
void CommunicationProtocolTest::testConnectToCammera()
{
QSignalSpy spy(communicationProtocol->m_socket, SIGNAL(connected()));
communicationProtocol->connectToCamera();
QTest::qWait(250);
QCOMPARE(spy.count(), 1);
}
My motivation was, if the response doesn't happen in 250ms, something is wrong.
However, the signal is never caught, and I can't say for sure if it's even emitted. But I've noticed that I'm not starting the event loop anywhere in the test project. In the development project, the event loop is started in main with QCoreApplication::exec().
To sum it up, when unit testing a class that depends on signals and slots, where should the
QCoreApplication a(argc, argv);
return a.exec();
be run in the test environment?
I realize this is an old thread but as I hit it and as others will, there is no answer and the answer by peter and other comments still miss the point of using QSignalSpy.
To answer you original question about "where the QCoreApplication exec function is needed", basically the answer is, it isn't. QTest and QSignalSpy already has that built in.
What you really need to do in your test case is "run" the existing event loop.
Assuming you are using Qt 5:
http://doc.qt.io/qt-5/qsignalspy.html#wait
So to modify your example to use the wait function:
void CommunicationProtocolTest::testConnectToCammera()
{
QSignalSpy spy(communicationProtocol->m_socket, SIGNAL(connected()));
communicationProtocol->connectToCamera();
// wait returns true if 1 or more signals was emitted
QCOMPARE(spy.wait(250), true);
// You can be pedantic here and double check if you want
QCOMPARE(spy.count(), 1);
}
That should give you the desired behaviour without having to create another event loop.
Good question. Main issues I've hit are (1) needing to let app do app.exec() yet still close-at-end to not block automated builds and (2) needing to ensure pending events get processed before relying on the result of signal/slot calls.
For (1), you could try commenting out the app.exec() in main(). BUT then if someone has FooWidget.exec() in their class that you're testing, it's going to block/hang. Something like this is handy to force qApp to exit:
int main(int argc, char *argv[]) {
QApplication a( argc, argv );
//prevent hanging if QMenu.exec() got called
smersh().KillAppAfterTimeout(300);
::testing::InitGoogleTest(&argc, argv);
int iReturn = RUN_ALL_TESTS();
qDebug()<<"rcode:"<<iReturn;
smersh().KillAppAfterTimeout(1);
return a.exec();
}
struct smersh {
bool KillAppAfterTimeout(int secs=10) const;
};
bool smersh::KillAppAfterTimeout(int secs) const {
QScopedPointer<QTimer> timer(new QTimer);
timer->setSingleShot(true);
bool ok = timer->connect(timer.data(),SIGNAL(timeout()),qApp,SLOT(quit()),Qt::QueuedConnection);
timer->start(secs * 1000); // N seconds timeout
timer.take()->setParent(qApp);
return ok;
}
For (2), basically you have to coerce QApplication into finishing up the queued events if you're trying to verify things like QEvents from Mouse + Keyboard have expected outcome. This FlushEvents<>() method is helpful:
template <class T=void> struct FlushEvents {
FlushEvents() {
int n = 0;
while(++n<20 && qApp->hasPendingEvents() ) {
QApplication::sendPostedEvents();
QApplication::processEvents(QEventLoop::AllEvents);
YourThread::microsec_wait(100);
}
YourThread::microsec_wait(1*1000);
} };
Usage example below.
"dialog" is instance of MyDialog.
"baz" is instance of Baz.
"dialog" has a member of type Bar.
When a Bar selects a Baz, it emits a signal;
"dialog" is connected to the signal and we need to
make sure the associated slot has gotten the message.
void Bar::select(Baz* baz) {
if( baz->isValid() ) {
m_selected << baz;
emit SelectedBaz();//<- dialog has slot for this
} }
TEST(Dialog,BarBaz) { /*<code>*/
dialog->setGeometry(1,320,400,300);
dialog->repaint();
FlushEvents<>(); // see it on screen (for debugging)
//set state of dialog that has a stacked widget
dialog->setCurrentPage(i);
qDebug()<<"on page: "
<<i; // (we don't see it yet)
FlushEvents<>(); // Now dialog is drawn on page i
dialog->GetBar()->select(baz);
FlushEvents<>(); // *** without this, the next test
// can fail sporadically.
EXPECT_TRUE( dialog->getSelected_Baz_instances()
.contains(baz) );
/*<code>*/
}
I had a similar issue with Qt::QueuedConnection (event is queued automatically if the sender and the receiver belongs to different threads). Without a proper event loop in that situation, the internal state of objects depending on event processing will not be updated. To start an event loop when running QTest, change the macro QTEST_APPLESS_MAIN at the bottom of the file to QTEST_MAIN. Then, calling qApp->processEvents() will actually process events, or you can start another event loop with QEventLoop.
QSignalSpy spy(&foo, SIGNAL(ready()));
connect(&foo, SIGNAL(ready()), &bar, SLOT(work()), Qt::QueuedConnection);
foo.emitReady();
QCOMPARE(spy.count(), 1); // QSignalSpy uses Qt::DirectConnection
QCOMPARE(bar.received, false); // bar did not receive the signal, but that is normal: there is no active event loop
qApp->processEvents(); // Manually trigger event processing ...
QCOMPARE(bar.received, true); // bar receives the signal only if QTEST_MAIN() is used

When is QThread quit() or finished()?

I'm new to Qt, and want to simply display a video in Qt GUI. I basically got everything figured out, except for some details handling the QThread, which is really annoying.
I reformulate my question into a simpler program, hope it will explains better
first I define this QObject class
#include <QObject>
#include <QDebug>
class myObject : public QObject
{
Q_OBJECT
public:
explicit myObject(QObject *parent = 0);
bool stop;
signals:
void finishWork();
public slots:
void dowork();
void onfinishThread();
};
myObject::myObject(QObject *parent) :
QObject(parent)
{
stop = true;
}
void myObject::dowork(){
qDebug()<<"start working!";
while(!stop){
qDebug()<<"working...";
}
emit finishWork();
qDebug()<<"finish do work!";
}
void myObject::onfinishThread(){
qDebug()<<"thread is finished!";
}
then the main function
#include <QCoreApplication>
#include <QThread>
#include <iostream>
#include <windows.h>
#include "myobject.h"
using namespace std;
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
myObject* myObj = new myObject();
QThread* myThread = new QThread;
myThread->connect(myObj, SIGNAL(finishWork()), SLOT(quit()));
myObj->connect(myThread, SIGNAL(started()), SLOT(dowork()));
myObj->connect(myThread, SIGNAL(finished()), SLOT(onfinishThread()));
myObj->moveToThread(myThread);
myObj->stop = false;
myThread->start();
cout<<"Press ENTER to continue....."<<endl<<endl;
cin.ignore(1);
myObj->stop = true;
Sleep(10);
if(myThread->isRunning()){
qDebug()<<"The thread is still running?!!!";
}
/*
myObj->stop = false;
Sleep(1000);
myThread->start();
myObj->stop = true;
*/
myObj->deleteLater();
myThread->deleteLater();
return a.exec();
}
As you can see, I even used cin to try let the dowork() run first, but it didn't work at all, the output is
so I'm really confused on how scheduling works for QThread...
Also, if you uncomment the part
/*
myObj->stop = false;
Sleep(1000);
myThread->start();
myObj->stop = true;
*/
the output is exactly the same! only stays a while after printing
The thread is still running?!!!
Would anyone help me with this? Thanks a lot. You may simply copy all the code and test it yourself.
-------------------------Original Question, bad explanation, please ignore....----------------------------------------
I made a videoObj Class with only one function to Query the frames, the function is defined as:
void videoObj::ProcessFrame(){
bool getframe;
qDebug()<<"get in ProcessFrame";
while(!stop_flag){
getframe = capture_.read(imgOriginal_);
if(!getframe){
qDebug()<<"Video End!";
break;
}
cv::cvtColor(imgOriginal_, imgOriginal_, CV_BGR2RGB);
QImage qimgOriginal((uchar*)imgOriginal_.data, imgOriginal_.cols, imgOriginal_.rows, imgOriginal_.step, QImage::Format_RGB888);
emit imgProcessed(qimgOriginal);
this->thread()->msleep(10);
//qDebug()<<"processing frames";
}
emit stopProcess();
qDebug()<<"Stop thread";
}
Basically above code is just query frames and whenever got one emit the
SIGNAL imgProcessed(qimgOriginal)
and whenever the stop_flag is set on, stop the while loop and emit the
SIGNAL stopProcess()
I use this class in the MainWindow Class, here is how I define the connection in the constructor:
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
video_obj_ = new videoObj();
video_thread_ = new QThread;
this->connect(video_obj_, SIGNAL(imgProcessed(QImage)), SLOT(onImgProcssed(QImage))); \\this is for displaying the image
video_obj_->connect(video_thread_, SIGNAL(started()), SLOT(ProcessFrame()));
video_obj_->moveToThread(video_thread_);
video_thread_->connect(video_obj_, SIGNAL(stopProcess()), SLOT(quit()));
}
Above code works fine in frame query. The problem I don't understand is, if I set video_obj_->stop_flag on in any MainWiow member function, the ProcessFrame() in videoObj Class should emit stopProcess() signal and trigger quit() of video_thread_, and then the thread should finish, that is video_thread_->finished() is true.
However, if I do something like:
connect(video_thread_, SIGNAL(finished()), this, SLOT(onStopProcess())); //onStopProcess() see below
void MainWindow::on_btnStart_clicked()
{
video_obj_->stop_flag = 1;
this->thread()->msleep(10);
video_obj_->capture_.open(ui->lineEditVidoeAddress->text().toStdString());
//... something about videoCapture setting here, not related
video_obj_->capture_.set(CV_CAP_PROP_POS_FRAMES, 0);
video_obj_->stop_flag = 0;
this->thread()->msleep(10);
if(video_thread_->isRunning()){
qDebug()<<"The thread is still running?!!!";
}
video_thread_->start();
}
void MainWindow::onStopProcess(){
qDebug()<<"thread is finished";
}
It will give me the output:
Stop thread
The thread is still running?!!!
thread is finished
Which means triggering the quit() is not finish the thread, or quit() has not been triggered.
If I use:
video_thread_->wait(); //instead of video_thread_->wait(10);
The program will just freeze.
Is anyone can help me with this, it really confuse me about this quit() and finished()...
Thanks!
Since when you call stop_flag=1, the video_thread_ finishes the current function which is
ProcessFrame
before ProcessFrame finish, quit is called on the video_thread_ through emit stopProcess().
However, quit is different from terminate, terminate can exit the thread any time (but it is not safe), quit works with the event loop, if the thread has no eventloop, quit has no effect.
I guess before qthread execute the next event in the eventloop, it checks some flag, which can be set by quit, it the flag is set by quit, then it won't execute the next event in the eventloop. Or it can also be that a quit event is inserted into the eventloop, and the next event in the eventloop will be quit.
After stop_flag = 1, you called video_thread_->wait, that will block the video_thread_ from executing the next event in the eventloop, thus the quit will not take effect before time out, however, the nextlines which print "not finished?!!!" is executed immediately. Instead of calling video_thread->wait, if you call currentThread()->Sleep(some_enough_time), then there will be time for the video_thread_ to execute the next event and quit.
You can read the Qt documentation of QThread, wait is used with terminate to terminate a thread synchronously.
============================== The new code ================================
When you do:
myObj->connect(myThread, SIGNAL(started()), SLOT(dowork()));
The signal source is myThread, the slot also belongs to myThread, since the object "myThread" is created in the main thread, thus as a object it lives in the main thread. You can call myThread->thread() to see this, it will return the main thread instead of the new thread.
However, the started signal is emitted from the new thread namely the thread that myThread represents, thus the connection is a Qt::QueuedConnection. dowork() is posted in the event queue of main thread, and it'll be executed only after a.exec() which executes the main threads eventloop.
The same thing happens to the other 2 connect calls, all the slots will be executed in the eventloop of the main thread.
First the start is emitted from the new thread when myThread->start is called, dowork is posted in the main thread's event queue.
Nothing really happens before you call a.exec();
So the program will go ahead to cin and then set stop to true, and then print "Thread is still running?!!".
Second When a.exec() is called, the dowork is executed in the main thread and "start work" is printed. Nothing is done because the stop flag is already true, and the finishwork signal is emitted from the main thread, print "finish do work";
Third The last step the finishwork is emitted, and the quit slot is directly called. However, before the new thread can really quit, the main thread has already finished the eventqueue, because no more events are posted to the main thread. The application exits without waiting for quit() to take effect.
To test this is true, do not modify any of your code, just add after
emit finishWork();
currentThread()->sleep(1000);
you will see "thread is finished!" printed, because this make time for the new thread to emit finished(), and the onfinishThread() will be add to the main thread's eventqueue.
BTW, your way of working with thread looks like java style, which is not the standard qt way. You can read this before you work on qt thread.
This is not a scheduling issue.
That you did in your code looks like:
Create a thread.
Then this thread emits a signal that it started, run slot dowork()
start a thread.
Wait for user input
echo about thread is running
execute event loop
At point 3 thread is already running and signalled about that. Because myObj is created in main thread and not moved to any other thread (to process events there), your thread does not do anything else now, but just spins event loop. At the same time event that tells you want to run myObj's dowork() is posted on the main thread. At last then it comes to step 6 you start to execute event loop of it, and first thing it finds is event that it needs to call dowork() on myObj.
To make it clear to you how Qt threads and signal-slot connection works, I recommend you to read this article on Qt blog.
In simple to fix it, you can move your object myObj to the thread that you wan't to run.
But to make this really correct, I bet that you really want is to subclass QRunnable and (re-)implement it's run method to do the stuff you wan't in QThread, so that thread does it's job, than finished correctly, so you can join on it. Or depending on your goal you might be even better with using QtConcurrent::run(aFunction)

Qthread - trouble shutting down threads

For the last few days, I've been trying out the new preferred approach for using QThreads without subclassing QThread. The trouble I'm having is when I try to shutdown a set of threads that I created. I regularly get a "Destroyed while thread is still running" message (if I'm running in Debug mode, I also get a Segmentation Fault dialog). My code is very simple, and I've tried to follow the examples that I've been able to find on the internet.
My basic setup is as follows: I've a simple class that I want to run in a separate thread; in fact, I want to run 5 instances of this class, each in a separate thread. I have a simple dialog with a button to start each thread, and a button to stop each thread (10 buttons). When I click one of the "start" buttons, a new instance of the test class is created, a new QThread is created, a movetothread is called to get the test class object to the thread...also, since I have a couple of other members in the test class that need to move to the thread, I call movetothread a few additional times with these other items. Note that one of these items is a QUdpSocket, and although this may not make sense, I wanted to make sure that sockets could be moved to a separate thread in this fashion...I haven't tested the use of the socket in the thread at this point.
Starting of the threads all seem to work fine. When I use the linux top command to see if the threads are created and running, they show up as expected.
The problem occurs when I begin stopping the threads. I randomly (or it appears to be random) get the error described above.
Class that is to run in separate thread:
// Declaration
class TestClass : public QObject
{
Q_OBJECT
public:
explicit TestClass(QObject *parent = 0);
QTimer m_workTimer;
QUdpSocket m_socket;
Q_SIGNALS:
void finished();
public Q_SLOTS:
void start();
void stop();
void doWork();
};
// Implementation
TestClass::TestClass(QObject *parent) :
QObject(parent)
{
}
void TestClass::start()
{
connect(&m_workTimer, SIGNAL(timeout()),this,SLOT(doWork()));
m_workTimer.start(50);
}
void TestClass::stop()
{
m_workTimer.stop();
emit finished();
}
void TestClass::doWork()
{
int j;
for(int i = 0; i<10000; i++)
{
j = i;
}
}
Inside my main app, code called to start the first thread (similar code exists for each of the other threads):
mp_thread1 = new QThread();
mp_testClass1 = new TestClass();
mp_testClass1->moveToThread(mp_thread1);
mp_testClass1->m_socket.moveToThread(mp_thread1);
mp_testClass1->m_workTimer.moveToThread(mp_thread1);
connect(mp_thread1, SIGNAL(started()), mp_testClass1, SLOT(start()));
connect(mp_testClass1, SIGNAL(finished()), mp_thread1, SLOT(quit()));
connect(mp_testClass1, SIGNAL(finished()), mp_testClass1, SLOT(deleteLater()));
connect(mp_testClass1, SIGNAL(finished()), mp_thread1, SLOT(deleteLater()));
connect(this,SIGNAL(stop1()),mp_testClass1,SLOT(stop()));
mp_thread1->start();
Also inside my main app, this code is called when a stop button is clicked for a specific thread (in this case thread 1):
emit stop1();
Sometimes it appears that threads are stopped and destroyed without issue. Other times, I get the error described above.
Any guidance would be greatly appreciated.
Thanks,
Bryan
http://mayaposch.wordpress.com/2011/11/01/how-to-really-truly-use-qthreads-the-full-explanation/
"Finally, to prevent nasty crashes because the thread hasn’t fully shut down yet when it is deleted, we connect the finished() of the thread (not the worker!) to its own deleteLater() slot. This will cause the thread to be deleted only after it has fully shut down."
Please try replacing:
connect(mp_testClass1, SIGNAL(finished()), mp_thread1, SLOT(deleteLater()));
with:
connect(mp_thread1, SIGNAL(finished()), mp_thread1, SLOT(deleteLater()));

Qt can not respond key Press event immediately

Environment: Ubuntu, Qt Creator
In my Qt app, I found that sometimes Qt doesn't respond to my key press event immediately, but if I wait a while, it eventually responds.
I think something is blocking the UI.
As I know, if a Qt's component (QWidget etc.) is being destroyed, the Qt UI will be blocked. I have checked my code, there is no component being destroyed at the time I'm pressing the up/down key.
I really want to know is there any other things can block Qt UI.
{
...
connect(webViewWidget, SIGNAL(loadfinished()), this, SLOT(addItem()));
...
}
void addItem()
{
delete webViewWidget; // will this delete block UI?
mListWidget = new ScrollWidget();
mScrollArea = new ScrollArea(this);
for(int i=0; i<Datalen; i++)
{
mListWidget->addSubItem(itemWidget);
}
}
void keyPressEvent(QKeyEvent *event)
{
switch(event->key)
{
case UP_KEY:
scroll up;
break;
case DOWN_KEY:
scroll down;
break;
default:
break;
}
}
In general, your key press event will not be processed before all other events which were put into the application's event queue before pressing your key are processed.
Therefore it could be any kind of event which has not finished processing. Maybe you can figure out if there are any events, e.g. by using QApplication::hasPendingEvents or by inheriting from QApplication and adding debug output whenever an event is added or fully processed.
Destruction of objects is usually not a concern, unless you are doing a lot of work in the destructor. Destroying a webview may take long. You probably should not be destroying it like you do. Instrument that delete (see code below) and see how long it takes.
Your own code may be calling APIs that block. Are you calling any third party libraries? Are you calling any wait... methods in Qt's own API?
If you're unsure, you can instrument every slot and every reimplemented virtual method like xxxEvent(...). You'd need to instrument only slots and reimplemented QObject/QWidget methods, not every method in your code.
You may be producing an event storm, perhaps by posting lots of events in a loop, or by sending a lot of signals that are hooked up to slots connected via a Qt::QueuedConnection. Make sure you're not calling repaint() from within paintEvent() for example.
The instrumentation example below uses RAII and is very easy to apply. Alternatively, you can use a profiler.
#include <QElapsedTimer>
#define INSTRUMENT() Instrument instr__ument(__FUNCTION__)
#define INSTRUMENTLIM(lim) Instrument instr__ument(__FUNCTION__, (lim))
class Instrument {
QElapsedTimer timer;
int limit;
const char * function;
public:
Instrument(const char * name, int timeLimitMs = 20) :
function(name), limit(timeLimitMs) { timer.start(); }
~Instrument() {
if (timer.elapsed() > limit) {
qDebug("%s was slow, took %d ms", function, timer.elapsed());
}
}
}
void slot(...)
{
INSTRUMENT();
...
}
void addItem()
{
INSTRUMENT();
delete webViewWidget; // will this delete block UI?
mListWidget = new ScrollWidget();
mScrollArea = new ScrollArea(this);
for(int i=0; i<Datalen; i++)
{
mListWidget->addSubItem(itemWidget);
}
}

Resources