Update Qt GUI in Loop ( show Bitmap image as movie ) - c++

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.

Related

QT update Linedit at runtime

I am trying to update the text on my linedit every time I get a frame, but my program crash. I tried doing the same with a loop, but the window shows only after the loop has finished. setH() is my slot, in Debug mode it run perfectly, the problem is when trying to update the text in LineEdit while the programm is running(the mainwindow is on the screen) . Thank you
void MainWindow::updatehand(){
if (controller.isConnected()){
int hc =frame.hands().count();
QString hndc= QString::number(hc);
emit hChanged(hndc);
}
void MainWindow::setH(const QString hndc){
handsRead->setText(hndc);
updatehand();
}
It is the reason for the crash:
connect(this, SIGNAL(hChanged(const QString)), this, SLOT(setH(const QString)));
Such connection is acutally a direct function call. The function setH() is called in place of emit hChanged(hndc);. Then the function updatehand() is called from setH().
It is an infinite loop with the stack overflow crash.
If you want to call updatehand() 60 times per seconds it is possible to called using QTimer, for example with QTimer statics memember:
void MainWindow::setH(const QString hndc){
handsRead->setText(hndc);
QTimer::singleShot(1000 / 60, this, SLOT(updatehand()));
}
Here updatehand() is also a slot.
In that case the even loop continues to dispatch UI messages after return from setH().
Approximately after 16 ms the timer will call updatehand().
The above solution technically breaks the infinite cross-refernce loop. However, it can be done better. There is a risk that setH() will be triggered many times from the external caller. In that case many timers will be activated.
It looks that you need just one QTimer instance to call periodiacally updatehand() independently of setH(). So, updatehand() can be pooled with given period to updated data. It can call setH() directly, the setH() function only sets the QLineEdit text:
void MainWindow::setH(const QString hndc){
handsRead->setText(hndc);
}

QLabel not updating from slot call

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.

Qt - GUI freezing

I wrote in C++ a solver for the 8-puzzle game, and now I'm trying to use Qt to give it a GUI.
Basically I have an underlying object of type "Board" which represents the board of the puzzle, and I have organized the GUI as a grid of QPushButton. Then I have a method updateUI which associates to every button the correct text, based on the Board. Something like
for(int i=0; i<Board::MATRIX_DIM * Board::MATRIX_DIM; i++)
{
m_buttons[i]->setText(m_values[i]);
}
In another method (solveGUI) I have
void MainWindow::solveGUI()
{
m_game->solve();
int solutionDepth = m_game->getSolutionDepth();
Move *solutionMoves = m_game->getSolutionMoves();
for(int i=0; i<solutionDepth; i++)
{
Move m = solutionMoves[i];
m_board.performMove(m); /* perform the move on the Board object */
updateUI(); /* should update the GUI so that it represents the Board */
Sleep(1000);
}
}
where the first line (m_game->solve) takes some time. Then I obtain a list of the moves performed, in solutionMoves, and what I would like to do is showing this moves on the board, with some delay between a move and the next one. This method is called by my main, which looks like this:
QApplication app(argc, argv);
MainWindow w;
w.show();
w.solveGUI();
return app.exec();
The result is that the GUI hangs and, after some time, it displays only the solution, completely skipping the moves.
What am I missing? Thank you!
P.S. I don't think I need a different Thread for the solver because I want the solver to run before the solution is displayed. Is it right?
It's app.exec() that actually runs the main loop which handles all events, including displaying GUI. If you want to call solve() before that, it's OK, but if you want to actually display and update GUI before exec(), it's wrong. I'm not sure if it's totally impossible, but it's definitely not the right way to do it.
There are two ways around it. The more canonical way is to redesign a program using a QTimer. Then everything will be smooth and responsive. But that can be tedious sometimes. In your case it should be quite easy, though. Just save the results somewhere, and call a slot using a QTimer object every 1000 seconds - it will have the same effect as your Sleep(), but will keep everything responsive.
The other solution is to call your solveGUI() method after exec() starts its job. It can be done, for example, using QTimer::singleShot():
QTimer::singleShot(0, &w, SLOT(showGUI()));
return app.exec();
Then, before each Sleep(), you should call QApplication::processEvents(), which basically allows you to temporary yield control, processing all pending events, including GUI updates. This approach is somewhat easier, but it's inferior since the GUI still freezes at each Sleep(). For example, if the user wants to exit the application, or if the window is needed to be repainted, it will cause uncomfortable GUI lags.
You're stalling the main thread (which also does the event processing) and rendering it uncapable of responding to keyboard/mouse/window messages.
You should use an asynchronous timer operation instead of the sleep function: use a QTimer to delay showing the next solution and avoid messages being left unanswered for too long.
There is a nice article of methods to keep the GUI responsive during processing loops. if it's not a complicated case I think, just insert QCoreApplication::processEvents(); inside the long processing loops.
try the following:
void MainWindow::Wait(int interval ) {
QTime timer = new QTime;
timer.restart();
while(timer.elapsed() < interval) {
QApplication::processEvents();
}
}
...
for(...) {
//wait 1 second (1000 milliseconds) between each loop run at first
Wait(1000);
...
}
...
not tested yet - but should work (maybe there is some cpu load)!

How do I progressively load a widget in QT?

I have a custom widget which displays many items in rows:
void update(){ //this is a SLOT which is connected to a button click
QVBoxLayout *layout = this->layout();
if (layout == NULL){
layout = new QVBoxLayout;
this->setLayout(layout);
} else {
QLayout_clear(layout); //this is a function that I wrote that deletes all of the items from a layout
}
ArrayList *results = generateData(); //this generates the data that I load from
for (int i = 0; i < results->count; i++){
layout->addWidget(new subWidget(results->array[i]));
}
}
The problem is that there are about 900 items and a profile reveals that simply adding the child object to the layout takes 50% of the time (constructing takes the other 50%). Overall it takes about 3 seconds to load all of the items.
When I click on the button to load more data, the entire UI freezes for the 3 seconds and then all of the items appear together when everything is done. Is there a way to progressively load more items as they are being created?
The first trick is, as Pavel Zdenek said, to process only some of the results. You want to process as many together so that the overhead (of what we're going to do in the next step) is low, but you don't want to do anything that would make the system seem unresponsive. Based on extensive research, Jakob Nielsen says that "0.1 seconds is about the limit for having the user feel that the system is reacting instantaneously", so as a rough estimate you should cut your work into roughly 0.05 second chunks (leaving another 0.05 seconds for the system to actually react to the user's interactions).
The second trick is to use a QTimer with a timeout of 0. As the QTimer documentation says:
As a special case, a QTimer with a timeout of 0 will time out as soon
as all the events in the window system's event queue have been
processed. This can be used to do heavy work while providing a snappy
user interface.
So that means that a timer with a timeout of 0 will be executed next, unless there is something else in the event queue (for instance, a mouse click). Here's the code:
void update() {
i = 0; // warning, this is causes a bug, see below
updateChunk();
}
void updateChunk() {
const int CHUNK_THRESHOLD = /* the number of things you can do before the user notices that you're doing something */;
for (; i < results->count() && i < CHUNK_THRESHOLD; i++) {
// add widget
}
// If there's more work to do, put it in the event queue.
if (i < results->count()) {
// This isn't true recursion, because this method will return before
// it is called again.
QTimer::singleShot(0, this, SLOT(updateChunk()));
}
}
Finally, test this a little bit because there's a gotcha: now the user can interact with the system in the "middle" of your loop. For instance, the user can click the update button while you're still processing results (which in the above example means that you would reset the index to 0 and reprocess the first elements of the array). So a more robust solution would be to use a list instead of an array and pop each element off the front of the list as you process it. Then whatever adds results would just append to the list.
#Adri is generally right, the twist is that the "another thread" must be the UI thread again. The point is to allow UI thread's event loop to keep spinning. The fast and dirty way is to put QCoreApplication::processEvents() in your for() cycle. Dirty because, as the doc says, it should be called "ocassionally". It might have some overhead even if there are no UI events, and you are messing Qt's performance optimization as to when and how often spin the loop. Slightly less dirty would be to call it only ocassionally, after chunks of result.
Cleaner and proper way is to create a private slot, which pops one result element (or chunk, to speed up), adds to the layout and increments index. Then it will recall itself until end of results. The gotcha is to define connect() with forced connection type Qt::QueuedConnection, so it will get deferred after already queued UI events (if any).
And because you run in only one thread, you don't need any locking over results.
Adding example per OP's request:
While #TomPanning solution is correct, it kind of hides the real solution behind QTimer which you don't need - you don't need any timing, you just need a specific non-timer behavior upon specific parameter value. This solution does the same thing, minus the QTimer layer. On the other hand, #TomPanning has a very good point about the plain ArrayList not being very good data storage, when interaction can happen in between.
something.h
signals: void subWidgetAdded();
private slots: void addNextWidget();
ArrayList* m_results;
int m_indexPriv;
something.cpp
connect(this,SIGNAL(subWidgetAdded()),
this,SLOT(addNextWidget(),
Qt::QueuedConnection);
void addWidget() {
// additional chunking logic here as you need
layout->addWidget(new subWidget(results->array[m_indexPriv++]));
if( m_indexPriv < results->count() ) {
emit subWidgetAdded(); // NOT a recursion :-)
}
}
void update() {
// ...
m_results = generateData();
m_indexPriv = 0;
addNextWidget(); // slots are normal instance methods, call for the first time
}

qt resize window after widget remove

I'm adding widget in layout
ui->horizontalLayout->addWidget(tabwidget);
and qmainwindow resizes itself. But then I do
tabwidget->setVisible(false);
qs = sizeHint();
resize(qs);
I get the size like tabwidget was not removed from window.
I've made new button
void MainWindow::on_pushButton_2_clicked()
{
qs = sizeHint();
resize(qs);
}
and it gives correct size.
Seems I need some update function but I can't find it. Please advice
This is caused by a long-time internal Qt issue (I remember experiencing it first with Qt3). The top widget needs to receive an event to truly update its geometry, and know its boundaries. This event seems to be always received after the resize event generated by the layout, and therefore it is always too late to shrink the widget.
The solution posted in the accepted answer works. However a simpler solution posted below also works, when added after the layout :
layout()->removeWidget( widget );
QApplication::processEvents( QEventLoop::ExcludeUserInputEvents );
resize( sizeHint() );
Basically all we need is to let the event loop run and deliver the necessary events so the top widget geometry is updated before resize() is run.
Note that this code might have side effects if you have multiple threads running, or there are events delivered to your slots. Hence it is safer not to have any code in this function after resize().
If the button slot gives you the correct result then you can always call the sizeHint() and subsequent resize() in a slot which is called by a single shot timer:
void MainWindow::fixSize()
{
QSize size = sizeHint();
resize(size);
}
void MainWindow::methodWhereIHideTheTabWidget()
{
tabwidget->setVisible(false);
QTimer::singleShot(0, this, SLOT(fixSize()));
}
This timer is set to zero delay. This means that the slot will be called immediatelly when the program returns to the main loop and hopefully after the internal widget state gets updated. If this doesn't resolve your problem you may try replacing zero with 1.