My QLabel is not updating from slot. I run sender class in separate thread using QObject::moveToThread:
QThread* serviceThread = new QThread;
service = new ExportService();
connect(service,SIGNAL(stateChanged(Service::ServiceState)),
this,SLOT(statusChanged(Service::ServiceState)));
service->moveToThread(serviceThread);
serviceThread->start();
Service object send states by emiting signal with ServiceState enum value, this signal is captured by QDialog slot:
void Dialog::statusChanged(Service::ServiceState s)
{
switch (s) {
case Service::IDLE:
qDebug() << "Idle";
ui->label->setText("Service send response succesfully.");
break;
case Service::REQUESTING:
qDebug() << "Requesting";
ui->label->setText("Requesting response from service...");
break;
case Service::ERROR:
qDebug() << "Error";
ui->label->setText("Error. Cannot get response from service.");
break;
default:
break;
}
}
After operation on the object which emits a signal twice, the first time with value of Service::REQUESTING and second time with value of Service::IDLE my QLabel change text only to "Service send response succesfully.". In the console I can see that qDebug() << "Requesting"; works so the state changed successfully.
After comment out ui->label->setText("Service send response succesfully."); label has changed to requesting state but after the whole operation was done ie i see "Requesting" in console then "Idle" and after that QLabel has changed.
What should I do if I want to see QLabel changing in realtime?
First, try adding update() after setText(), chances are setText() doesn't automatically schedule a repaint() for the QLabel, if it works then problem solved.
However, for update() function:
http://doc.qt.io/qt-4.8/qwidget.html#update
void QWidget::update()
This function does not cause an immediate repaint; instead it
schedules a paint event for processing when Qt returns to the main
event loop. This permits Qt to optimize for more speed and less
flicker than a call to repaint() does.
> Calling update() several times normally results in just one
paintEvent() call.
which basically says, if you call them too frequently and some of them will be optimized away.
If this is not the desired behaviour, try adding a forced repaint() after setText(), or using a timer to schedule periodical forced repaints.
http://doc.qt.io/qt-4.8/qwidget.html#repaint
UPDATE
As is mentioned in the comment, forcing repaint() isn't good solution.
This answer is intended to provide an analysis of the cause of the code's behaviour and the "forced repaint()" suggestion is more of a way to verify this analysis than a solution to the problem.
However, without further information on the purpose of the program, it's very difficult to provide further suggestions.
The status change from requesting to idle happens quickly. The text "Requesting response from service..." is not on the label long enough for the eye to see it.
The fact that "Requesting ..." is in the debug output is proof of this, but if you want more proof there are other things you could do:
use a counter that counts each time the statusChanged() function is called and display this either in the same label as the status text (in addition to the status text) or a different label.
add a high accuracy timer output to the debug outputs - see how close together the status changes are.
use a couple of check boxes, one for idle status and one for requesting status. Change their state when the appropriate status is received. That is whne the first Idle is received set the check box to checked. When the next idle is received toggle it to unchecked.
I would just accept that the debug outputs are telling the truth and move on.
Related
I have an application that continuously reads an image from a camera and displays this to a user. The user can adjust different sliders such as exposure and threshold to modify the image in real-time. I also do a bunch of calculations on this image afterwards which sometimes makes the GUI unresponsive, so I decided to use threads to divide the workload.
However, I can't get it to work properly, sometimes I get segmentation faults and a bunch of "assertion ` GLib-GObject-CRITICAL **: g_object_unref: assertion 'G_IS_OBJECT (object)' failed" warnings when the slider values are changed or if I try to save the image (save button in my GUI), and the GUI sometimes stops updating the image or freezes so you can't move the sliders or push any buttons.
What I tried to do was to use the standard std::thread in C++, and connect it to the start button through a slot.
QObject::connect(btnStart, SIGNAL(clicked()), this, SLOT(RunStartThread()));
void MainMenu::RunStartThread(){
std::thread t1;
t1= std::thread(&MainMenu::Start,this);
t1.detach();
}
void MainMenu::Start() {
run = true;
window->mngr->ReadCalibration();
window->mngr->InitializeCameras();
while (run) {
window->mngr->CaptureImage();
window->mngr->ProcessImages();
UpdateLabels();
}
window->mngr->Stop();
}
When the user changes the slider values they change variables in my manager (mngr above) that captureImage and ProcessImages uses. I tried using a std::mutex lock/unlock when a variable was to be accessed, but it did not change anything. I've tried to find examples of how to do this online, but have yet to find something that has a continuous while-loop.
I'm a newbie when it comes to threads, so just tell me if I'm approaching this in the wrong way.
First for all for inter thread communication use singnals and slots. By default Qt connections do nice thread hopping between threads which lets to avoid complex synchronization.
Secondly you have three ways of using threads: QThread, QRunnable, QtConcurrent::Run (my favorite, since requires minimum amount of code).
In case QThread please do not subclass it! It is common design mistake.
Example:
SomeClass::~SomeClass()
{
SignalStop();
future.result();
}
void SomeClass::RunStartThread(){
future = QtConcurrent::run(this, &SomeClass::DoOnThread);
}
void SomeClass::DoOnThread()
{
while (ShouldContinueToRun()) {
QImage im1 = CaptureImage();
emit ImageCaptured(im1);
QImage im2 = ProcessImages(im1);
emit ImageProcessed(im2);
}
emit JobCompleted();
}
Please note that QObject::connect has last argument which defines how invocation of slot is performed if different thread is involved. See documentation of enumeration used for this argument.
So by default Qt detects if thread hopping is needed or not. Reading carefully about QObject::moveToThread should also help to understand the problem (note you can't move object to different thread if it has a parent).
The way I am working now is to connect a QTimer to the first slot, inside the first slot it will trigger another single-shot QTimer which will trigger the second slot... and so on.
If I update all of the widgets at once, the GUI will stuck for a flash of a second. But it is noticeable. So I want to avoid that.
But this is very difficult to write code. You have to add QTimer everywhere. Are there any better solutions?
EDIT: This is how I update my widget, maybe there is better way?
void UAVInfoView::updateDisplay()
{
if (!visibleRegion().isEmpty()){
info = _dataSrc->getUAVInfo(_id-1);
if (info)
{
//if new package received try to do updating.
if (_pakchk != info->_pakcnt){
//only update the text if there is communication
if (info->_communication != COMMSTATUS::WAIT4CONNECTION && info->_communication != COMMSTATUS::LOST)
{
ui->plainTextEdit->setPlainText(tr("x: %1\ny: %2\nz: %3").arg(info->_pos[0]).arg(info->_pos[1]).arg(info->_pos[2]));
}
//only update the status indicator only if status changed.
if (_status != info->_communication)
{
switch (info->_communication){
case COMMSTATUS::CONNECTED:
ui->groupBox->setStyleSheet("QGroupBox#groupBox {background-color:green;}");
ui->label_2->setText("On Line");
break;
case COMMSTATUS::LOST:
ui->groupBox->setStyleSheet("QGroupBox#groupBox {background-color:red;}");
ui->label_2->setText("Lost");
break;
case COMMSTATUS::WAIT4CONNECTION:
ui->groupBox->setStyleSheet("QGroupBox#groupBox {background-color:grey;}");
ui->label_2->setText("Off Line");
}
}
}
//update the status and package counter to serve the state machine.
_status = info->_communication;
_pakchk = info->_pakcnt;
}
}
}
As you can see, it is just a bunch of default =, ! if else things...
You can call them in a slot connected to a timer with a certain interval. Your slot that is connected to the timer could be like :
void myClass::onTriggered()
{
switch(turn){
case 0:
slot1();
break;
case 1:
slot2();
break;
...
}
turn++;
if(turn>=numberOfSlots)
turn = 0;
}
This way each time one slot is called and they are called sequentially.
I'm not quite sure what you try to achieve, but if you want to trigger the execution of a specific set of functions with a timer, you probably have to introduce some controlling instance with a singe QTimer that you can use as often as you like.
Now that you said you don't want to update all your GUI widgets all the time, and I guess you are using QWidgets, you could also use the setUpdatesEnabled(bool) method to disable all effects of update() or repaint() calls.
If this doesn't help you, maybe you can explain you problem a bit more detailed?
Although I believe the problem is somewhere else, I'll give you one possible solution. You could use a state machine. Just have one slot that is triggered by your timer in which you call some other functions based on the current state.
...
connect(&timer, SIGNAL(timeout()), this, SLOT(myStateSlot()));
timer.start(1000);
...
void MyClass::myStateSlot()
{
switch(state)
{
case State_Start:
operation1();
// you can change the state here.. or somewhere else.. up to your design
break;
case State_Two:
operation2();
break;
case State_End:
timer.stop();
break;
}
}
Your problems likely stem from the relative slowness of the QPlainTextEdit. Use a QLabel instead. Otherwise, the code looks fine. Make sure that if there are multiple consequent calls to updateDisplay, they should all happen without the control returning to the event loop between the calls.
The below is wrong, since each processEvents forces a repaint of the widgets.
w.updateDisplay();
QCoreApplication::processEvents();
w.updateDisplay();
QCoreApplication::processEvents();
You might be invoking processEvents() without realizing it. It is effectively invoked every time you return from QObject::event() and the event queue is empty at the time. Also note that QObject::event() is the caller of queued slot calls. Thus, if you have a queued connection to a slot, the control returns to the event loop right after the slot returns.
If the update method is complex, you should try QtConcurrent::map() to run the update in another thread. Then you need no delay, because you'll get notified from map() when the updates are finished.
I'm using QtConcurrent to do some heavy background image processing and I want to display the image while parts of it are being updated progressively.
Each line of the image is computed separately and is passed a functor.
To compute the full image I then have a sequence of item that I pass to QtConcurrent mapped and each line emits a signal when it is done computing
Here is the instantiation of the class Worker:
//living in the main(gui) thread !
Worker::Worker(VideoEngine* engine):_engine(engine){
_watcher = new QFutureWatcher<bool>;
_watcher->setPendingResultsLimit(200);
connect(_watcher, SIGNAL(resultReadyAt(int)), this, SLOT(onProgressUpdate(int)));
connect(_watcher, SIGNAL(finished()), engine, SLOT(engineLoop()));
}
Here is the slot to report progress:
void Worker::onProgressUpdate(int i){
if(i < (int)_rows.size() && i%10==0){
cout << " index = " << i << " y = "<< _rows[i] << endl;
_engine->checkAndDisplayProgress(_rows[i],i);
}
}
Now the usage:
void Worker::_computeTreeForFrame(.../*unrelevant args*/){
....
....
_watcher->setFuture(
QtConcurrent::mapped(_sequence,
boost::bind(&VideoEngine::metaEnginePerRow,_1,output)));
}
}
All the signals are emitted but the slot onProgressUpdate gets called only when Qtconcurrent::mapped is done with all the items in the sequence.
When executing it has a huge delay while the sequence is processing and then all slots are executed sequentially afterwards.
I have tried all types of signal/slots connection and none of them changed this behaviour.
Any clue ?
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
EDIT after Shf suggestion
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
The call was made until now in the main(gui) thread.
I changed the call to :
_computeFrameWatcher->setFuture(QtConcurrent::run(_worker,&Worker::computeTreeForFrame));
Since _computeTreeForFrame is now executed in another thread, I changed the call to QtConcurrent::mapped to:
_watcher->setFuture(QtConcurrent::mapped(_sequence,
boost::bind(&VideoEngine::metaEnginePerRow,_1,output)));
_watcher->waitForFinished();
This results in exactly the same behaviour as before.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
EDIT after Marek R suggestion
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ok so I made so tests and here is what I observed:
QtConcurrent::map :
Doesn't emit the signal resultReadyAt(int)
QtConcurrent::mapped
Emits resultReadyAt(int) only when finished
It doesn't matter if the call to the map function is done in a separate thread the same behaviour is encountered.
I also gave a try to the signal progressValueChanged(int) as the Qt progressDialog example suggests.
The signal progressValueChanged(int) gets emitted only for 2 lines in the image (the first and last).
This is really weird as in the Qt progress dialog example it is emitted smoothly.
I changed a bit the Qt example to launch the map function in another thread than the main thread and it still works well in that case.
The issue must arise from somewhere else.
Maybe the GUI event loop is doing something I don't expect ? I have no clue what.
I will now try QtConcurrent::mappedReduced and report with the results :-)
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
EDIT after giving a try to QtConcurrent::mappedReduced
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
It doesn't work and calls the "reduce" function ONLY when the "map" function is done. In other words it does the same than the previous signal/slots mechanism.
I'm running low in possibilities now
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
EDIT I'm back to a solution as close as the Qt progress dialog example
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Something must be wrong if I can't get the same behaviour than the Qt example.
Here's the code now:
//created in the main thread! (gui)
Worker::Worker(VideoEngine* engine):_engine(engine),_watcher(0){
_watcher = new QFutureWatcher<void>;
_watcher->setPendingResultsLimit(200);
connect(_watcher,SIGNAL(progressValueChanged(int)), _engine,
SLOT(onProgressUpdate(int)));
connect(_watcher, SIGNAL(finished()), engine, SLOT(engineLoop()));
}
//executed on the main thread
void Worker::computeTreeForFrame(...){
...
_watcher->setFuture(QtConcurrent::map(_sequence,boost::bind(metaEnginePerRow,_1,output)));
...
}
The call to computeTreeForFrame...
...
_worker->computeTreeForFrame();
...
This call is done in a slot .
It emits the signals for the line 0 and for the last line as told before but doesn't emits anything else.
Shouldn't this do EXACTLY what the Qt example does?
From task description it looks like you should use mappedReduced. Problem is that I don't see a good way to get partial results. One way to overcome this problem is to emit signal form reduce function.
It is possible that this thread may help.
It seems, that QtConcurrent::mapped does not put VideoEngine::metaEnginePerRow in another thread, judging by the documentation. If image is processed in the same thread as GUI, then your slots indeed will be executed after processing, no matter what type of connection you select, just as you've described.
The solution is to either run Worker::_computeTreeForFrame (as i understood, your main processing function) in another thread via QtConcurrent::run or to put your Worker object in another thread probably via QObject::moveToThread(). Then, the connection type you should use is Qt::QueuedConnection (or if you will put Worker in another thread before connection, you can connect even with Qt::AutoConnectionor Qt::UniqueConnection, caller and receiver will be in a different threads, so qt will automaticly chose QueuedConnection`)
EDIT:
I'm not sure, but your _watcher = new QFutureWatcher<bool>; is still created in the main thread and if you call
_watcher->setFuture(QtConcurrent::mapped(_sequence,
boost::bind(&VideoEngine::metaEnginePerRow,_1,output)));
_watcher->waitForFinished();
would _watcher set GUI thread to wait, in what it was created or thread, where this command is executed. If _watcher->setFuture(QtConcurrent::mapped(_sequence,
boost::bind(&VideoEngine::metaEnginePerRow,_1,output))); if the end of a function, is _watcher->waitForFinished(); needed at all? Qt will destroy thread right after it's execution and you set your processing function to run, why wait?
And _computeFrameWatcher should be of QFuture<void*> type.
EDIT2:
Ok, before i give up, i suggest you to test QObject::moveToThread:
before you call _worker->computeTreeForFrame(); , put it in another thread:
QThread *workerThread=new QThread();
_worker->moveToThread();
_worker->computeTreeForFrame();
/* connect _worker's finished signal with workerThread::quit and deleteLater slots */
and all connections within _worker should be DirectConnection and all connections between _worker and main (GUI) thread should be connected with QueuedConnection. Also it's probably good to create new thread in _worker constructor and move it to another thread immediately, this way you can destroy thread in _worker's destructor and don't worry about thread problem's in GUI thread
I have run into an interesting problem with WT, I have solved it, but I do not understand WHY my solution solved the problem. I've dug through WT documentation for the widgets and have come up empty handed so far, so maybe someone who knows more about WT can help me out here.
Anyway, the problem is with a WComboBox widget in a boost thread not updating it's data when clicked on and having it's selection changed.
I created a boost thread in a class
class MyConsole: public WApplication
{
private:
boost::shared_ptr<boost::thread> _thread;
WComboBox* _combo_box;
bool running;
//Thread function
void my_thread(Wt::WApplication *app);
}
Then I fill the combo box with data, lets use "foo" and "goya" as the 2 entries. I made a function for the thread, and put a loop into it.
void MyConsole::my_thread(Wt::WApplication *app)
{
while(running)
{
std::string test;
Wt::WApplication::UpdateLock lock(app);
if(lock)
{
test = _combo_box->valueText().narrow();
}
if (strcmp("foo", test.c_str()) == 0)
{
cout << "we got foo" << endl;
}
else if (strcmp("goya", test.c_str()) == 0)
{
cout << "we got goya" << endl;
}
}
}
Without changing the initial selection of the combo box, the above code always enters the foo if statement, which is expected. However, when I change the selection of the _combo_box to "goya" the above code still enters the "foo" if statement, which is very unexpected. Investigating the matter further such as printing out the current index of the combo box before the if statement showed me that it is always 0 and never gets incremented when the selection changes.
The way I fixed it was by connecting the combo box changed() signal to a do nothing function that I added to the class.
class MyConsole: public WApplication
{
private:
...
void WWidgetForceUpdate(void)
{
}
...
}
...
_combo_box->changed().connect(this, &MyConsole::WWidgetForceUpdate);
With the addition of that function call when the selection changes, the "foo" and "goya" if statements worked properly, and printing out the current index of the combo box before the if statement confirmed that the index was now changing.
Why did connecting the changed() signal to a do nothing function remedy the situation? I am sure there is a bigger problem that I am not seeing here :(
Any help would be much appreciated.
Wt sends changes from the browser to the server when events happen. If your program is not interested in an event, this synchronisation will not take place (otherwise synchronisation would take place on every character of text you enter in an input box, on every mose movement, .... even if your application is not doing anything with it). Nothing connected to changed() means that nothing is interested in that specific event, and the browser will not notify the server when it happens.
Any event that is being listened upon will send all changes of all widgets to the server, so that the full widget tree is synchronised. So if you have a button with clicked() listener, and a combobox without a changed() listener, the state of the combobox will still be updated in the widget tree when you click the button.
There is however a bug in your code: you cannot just access the widget tree from a random thread without grabbing the update lock (WApplication::UpdateLock).
i receive screenshot as bitmap from socket and when i show only one of them it work
but when i put in loop ( show all receive image to make movie) i get hang
void ShowImageBuffer(char* buf,int sizeofimagebuffer )
{
QByteArray byte=QByteArray::fromRawData(buf, sizeofimagebuffer );
QPixmap image;
if(image.loadFromData(byte,"BMP"))
{
ui->label->setPixmap(image);
ui->label->update();
}
}
while(1)
{
ShowImageBuffer(buf, sizeofimagebuffer)
}
i must use separate thread?( but i think we will not use any thread to change GUI?)
what is best to make it real time?
The problem I suppose is that you're not returning to the event loop this way. The update() method you're using doesn't repaint the QWidget immediately. It schedules a request to update the area, which is unified with other pending requests if any is available. This request is processed when the execution returns to the event loop. It is clearly stated in the documentation.
You might want to use a QTimer and invoke the ShowImageBuffer method at a specific frame rate. When the ShowImageBuffer is finished, execution returns to the event loop thus giving the time to process the update() request. Also consider the improvement suggested by AJG85.
Otherwise you can have a look at the repaint() method which immediately invokes the paintEvent() method, but still I suppose you should set a specific frame rate to get a good result. I would go with the QTimer way.