QProgressDialog "closes" when another process is started - c++

In my project, I have a function running while a QProgressDialog shows the progress.
QProgressDialog progress("Saving savegame.dat...", "Abort Save", 0, 3016, this);
progress.setWindowModality(Qt::WindowModal);
//... some loops and other calculations run while I update the progress bar with:
progress.setValue(1000);
All is well until I start another process. (Open a cli program)
QProcess decomBR;
QStringList filePathListBR;
filePathListBR.append("-o");
filePathListBR.append("stuff\\compress.bms");
filePathListBR.append("stuff\\regions\\xbox_chunks\\br");
filePathListBR.append("stuff\\regions\\xbox_chunks\\br");
decomBR.start("stuff\\quickbms.exe", filePathListBR);
decomBR.waitForFinished();
As soon as a process like this is started, the progress bar dialog hides or something and the progress is no longer shown, but the processes still run fine.
Any way to prevent these processes from "closing" the QProgressDialog?
EDIT: So apparently, the dialog isn't closing, it's just the main window is taking priority and "covers" the dialog... if that makes sense. Is there any way to make the dialog maintain display priority?
Thanks for your time :)

I have not tried this, but setWindowFlags(Qt::WindowStaysOnTopHint); may help. Notice that it's a flag, so you'd want to write something like:
progress.setWindowsFlags( progress.getWindowsFlags() | Qt::WindowStaysOnTopHint );
Consider using an assertion to see if it's already set, if so then you can dismiss my answer definitively and add to human knowledge by negation!

Related

Qt 4.8.5 Understanding QMessagebox .exec() and .show()

I'm doing a QWizard with QT 4.8.5 and in some pages I have to close some other applications and exit my program. This works fine but now I want to show a pop up message that tells the user that the programs are restarting (There are others a part of mine and mine is the last one to be closed always). The code I use to show the pop up is the next one and I place it in the validatepage of a QWizardpage:
QMessageBox *msgBox1 = new QMessageBox;
msgBox1->setWindowTitle("Title...");
msgBox1->setIcon(QMessageBox::Information);
msgBox1->setText(" blablablalbal bla bla bla.");
msgBox1->setWindowModality(Qt::NonModal);
msgBox1->show();
QCoreApplication::processEvents(); // without this line, the show does nothing and I can't see my pop up window
So the thing is: With that code, When I am in that wizardpage and click to finish, it launches the QMessageBox while (behind) the program is restarting the other applications and then closes itself (with a QApplication::quit(); ) which is exactly what I want... BUT no message is shown in the pop up... I can't see the icon, the title or the text... :S I don't know why :(
Whereas when use ->exec(); instead of show, the icon, title and text are shown BUT when the pop up appears, nothing is done behind until the user closes that pop up... :S
I understand that .exec() freezes all until user closes the pop up while show doesn't...
So... how can I see the text with the show() behaviour?? I don't want the user to interact with that pop up, I just need the pop up to show up while closing all until my program closes too...
Thank you so much!
Relevant: http://comments.gmane.org/gmane.comp.lib.qt.general/30706
In summary, QDialog::exec() creates a modal dialog (regardless of your Qt::NonModal setting) with its own event loop, and ::show() does not.
So in your case, ::exec() will fully render the dialog but it's blocking the rest of your background processing. ::show() won't block, but since it's sharing the event loop with your other code it isn't getting around to emptying the event queue (which has all of the show/layout/render events from your dialog) because of your background code.
I would try the following:
use ::show() not ::exec()
force your dialog to the front using QDialog::raise() and Dialog::activateWindow()
(the important part) either
call QApplication::processEvents() within your background processing tasks (e.g., within long-running loops).
spawn your background processing into a thread (this may or may not be easy depending on how your code is structured) to allow the main event loop to process your dialog events.

Qt QProgressBar indeterminate

My application needs to do some operations which might take a second but might also take 10 minutes. For this purpose I need to show a QProgressDialog with indeterminate QProgressBar during the operation.
QProgressDialog dlg( this );
dlg.setBar( new QProgressBar() );
dlg->setMaximum( 0 );
dlg->setMinimum( 0 );
dlg.setModal( true );
dlg.show();
//operation ...
dlg.close();
During my operation the dialog shows up, is transparent, has no progressbar and after the operation it closes.
Does anyone know what I can do to show a modal dialog which prevents the user from interacting with the application and which shows the user an indeterminate progressbar?
I'd suggest you don't create your own QProgressBar. The QProgressDialog has its own bar inside, and propagates all the methods from dialog to bar. What's more, to make your window modal use exec not show, or setModal(true) first. To close it, connect some signal (of a finished work) to the cancel() slot (or user will have to click Cancel button).
QProgressDialog dialog;
dialog.setRange(0,0);
dialog.exec();
I think one thing that you might need is that you call QApplication::processEvents() while looping over your entries.
Quoting from QCoreApplication docs:
You can call this function occasionally when your program is busy performing a long operation (e.g. copying a file).
and I think in this particular case the application will not update the appearance of your QProgressDialog while it is busy performing the long operation unless you call QApplication::processEvents().
If you have fixed range and you call setValue() as your loop progresses (quoting from the QProgressDialog docs):
If the progress dialog is modal (see QProgressDialog::QProgressDialog()), setValue() calls QApplication::processEvents()
(I am omitting here the warning which cautions that this can cause issues with re-entrancy).`
Note that when I tried your code it created a dialog like what you would expect if you only remove the line
dlg.setBar( new QProgressBar() );
As was said in another answer, QProgressDialog has its own QProgressBar so unless you have special requirements, this should do what you need.
The documentation of the QProgressDialogs method setBar states, that "... the progress dialog takes ownership of the progress bar ...", however I found a forum post about the exact same problem you have.
In that post the last answer of the user ShaChris23 states, that this problem can be solved by passing the pointer to your QProgressDialog in the constructor of the QProgressBar, to set it as parent:
dlg.setBar( new QProgressBar(&dlg) );

Qt problem: No QProgressBar animation with minimum and maximum steps set to 0

I have got a problem with my QProgressBar and I hope someone got an idea...
I have created a progress dialog with a QProgressBar on my own. I set minimum and maximum steps to 0 so that the progress indicates my program is busy (the animation thing...).
I show() this progress dialog and activated the Qt::WindowModal for this dialog.
The problem: I use this dialog while copying files but the progress bar stops and no animation anymore to indicate my program is still busy. I use the windows function 'SHFileOperation' to copy one directory with a lot of file to a destination. This, of course, produces a lot of load on the system but at least the progress should continue moving.
Any help is appreciated!
Thanks in advance,
BearHead
The problem is that the SHFileOperation call will block the main event loop. Therefore, no events will be processed preventing the QProgressBar from being updated.
To fix this you could perform the copy action in a separate thread. The easiest way to go about this is using Qt Concurrent, for example as follows:
QFuture<void> future = QtConcurrent::run(SHFileOperation, ...);
QFutureWatcher<void> watcher;
connect(&watcher, SIGNAL(finished()), dialog, SLOT(close()));
Assuming dialog is a pointer to your progress dialog.
Btw, why do you use SHFileOperation instead of the operations provided by QDir and QFile?

FindWindowEx not able to find window handle

I am trying to find the handle to a dialog as soon as it opens.
Now as soon as dialog is opened I try to call FindWindowEx for that dialog in a separate thread but it returns NULL.
I then put some sleep before calling FindWindowEx. It works some time after putting sleep.
It looks like FindWindowEx is getting called before even dialog is created and sleep is helping to create the dialog and hence some times it work.
Now I have put some random value in sleep. And it doesnot look a good approach since it can fail anytime.
Is there any full proof approach so that I may get handle every time via FindWindowEx without making thread to sleep.
If the dialog you are looking for is your dialog -- that is, you control the code -- then you can send a message from your dialog to your watching app that says, "Oh, hi there!"
If the dialog is not yours, and you don't want to spin, you can create a Windows hook on the WM_CREATE message.
A very straightforward solution would be to call FindWindowEx repeatedly in a loop.
HWND h = NULL;
while (1) {
h = FindWindowEx(...);
if (h) {
break;
}
Sleep(100);
}
That's not bullet-proof - it's an infinite loop if the dialog nevers opens, or is closed too quickly (although that's unlikely). To catch both cases, let the main thread (which creates and runs the dialog) maintain a simple bool property that the worker thread queries to find out whether there's still a dialog around.

QT Repaint/Redraw/Update/Do Something

I'm New to QT. I understand that you can force a display refresh, but I've pulled all my hair out trying to figure out how. Here is what I'm specifically trying to do.
I press a button (onClick signal event), which runs code that changes an image (QLabel) on the display, waits for input, and then proceeds by changing a new image (different QLabel). I've tried everything and the display doesn't refresh until the onclick signal event code is complete. Right now, I'm not waiting for user input, I'm using usleep(~500 ms) for testing purposes.
From what I read, QT is event driven meaning that I'm basically creating a bunch of events, that get put in a que, and executed when the (onClick signal event) returns to the (main loop)/(event handler). I don't want to wait until the function is complete, it's going to make programming extremely painful if I have to accomplish this routine entirely based on events.
How can I force the QLabel pixmap to refresh. I've tried everything. Below is all the code I have tried in my onClick signal event handler. (upButton is the name of the QLabel which is a pixmap)
update();
repaint();
ui->upButton->setUpdatesEnabled(TRUE);
update();
repaint();
QPaintEvent paintevent(ui->upButton->childrenRegion());
QPaintEvent * test = &paintevent;
paintEvent(test);
this->changeEvent(test);
ui->upButton->update();
ui->upButton->repaint();
ui->upButton->repaint(ui->upButton->childrenRegion());
repaint();
QApplication::sendPostedEvents();
this->parentWidget()->update();
usleep(100000);
As you can see, I'm just shooting in the dark at this point. I've tried to look at sample code and do all my homework, but I'm lost. Appreciate any help, advice, and or sample code.
I was using sleep to emulate a brief amount of time the computer was waiting for something to happen.
As I stated in my question, I didn't want to use events because it's a whole lot of unnecessary work to accomplish something extremely simply.
Also, the 'event' that needs to take place for the program to continue, is a USB event. Since I'm using an HID class device, there is no way to set an event to happen without a wait loop. USB HID classes don't permit setting interrupts, the OS claims the device.
I managed to get the above to work. I walked through the debugger and noticed the display would refresh before the sleep function. Running the program independently, I got random results with the display refreshing 1% of the time. I got rid of the sleep function, and added some other code in it's place to emulate a delay, and it was fine.
Just for everyone's knowledge, this is possible, it's not forbidden, and it's easy to do with the following:
qApp->processEvents();
qApp is a global external variable in the QApplication header.
Because this USB event is making my flow tricky, I stumbled upon the QWaitCondition Class. I was going to start a process waiting for the USB event. I would wait until the process releases the wait condition for my routine to continue.
But if anyone thinks this is a bad idea, please, speak out. I really do appreciate your feedback PiedPiper and Hostile Fork.
Thank you.
I noticed sometimes when you have multiple layered widgets, or widgets inside of widgets it helps to call their repaint() events.
For example
this->repaint();
this->parentWidget()->repaint();
this->parentWidget()->parentWidget()->repaint();
This is far easier then pushing out any processing to another Thread, or creating additional event handlers.
You shouldn't be waiting for input in your event handler. You need to rethink the logic of your program to use events the way they were intended. All the update() and repaint() calls in your code are unnecessary if you return to the event loop.
If i understood correctly, you have a slot and in this slot, you update the image shown in a QLabel. But you want this change to be displayed before the slot finishes.
If that is the case, issue an update() event, and call qApp->processEvents(). This method processes events that are waiting in the event queue and then returns, therefore this may be what you are after.
PS: an update() may not be necessary at all, i am not sure.