How to preload QDialog before it is shown? - qt

I have a QT application, which creates a dialog which has a bunch of tab pages, which each have a lot of Widgets.
I know there isn't going to be a way to get around how long it takes to load the widgets in as there are quite a few.
I've thought about after the main window being initialized, if there is something I can do to load the dialog in the background, so when show is clicked it is a faster experience.
Are there any techniques to preload dialogs, perhaps after the main window has loaded? When I say preload, I mean the 'new QDialog(..)...' process. That seems to be where the latency is as then that constructor begins laying out all the components and so on. the .show() isn't the issue as that runs instantly.
QCustomDialog * customDialog = new QCustomDialog(); // the latency
customDialog->show(); //not the latency
class QCustomDialog {
QCustomDialog::QCustomDialog() {
//creation of many nesscary widgets and added to the dialog
QLabel * lab = new QLabel("Label 1");
...
};
};

If you just need to let the user know the application is starting, and it takes a few seconds before the main window loads, you could use QSplashScreen.
This allows you to display an image while the main window loads. If the application takes more than a few seconds, and it makes sense for your application, you can also use QSplashScreen::message() to display messages as different parts of the app are loading.

Related

Using QT 4.7 - dialog is busy loading a BIG thing; how to disable all controls?

[EDIT] - wasn't getting to the disable code the way I thought I was; works fine with any of the solutions below.
I have a modeless QT dialog, in which all kinds of user settings can be manipulated. In addition, it can save and load large data sets, which can take several seconds. Lots going on in the main window underneath (realtime app) and that's fine, and interaction there is okay, but in the dialog itself, I need to block user interaction.
Essentially, during the load, I don't want the user to be able to change / affect any of the controls in the modeless dialog (and there are a lot of them.)
Rather than disable each one individually (or even that way if that's the only way), is there a straightforward means I can use to disable input to the dialog entirely until the load is complete?
There's a progress bar in it that shows what's going on, too, which is constantly updated by the load process, so that needs to keep on working.
I tried this...
On dialog open:
QDialog *window = this;
Then around load:
window->setDisabled(true);
....
window->setDisabled(false);
...which compiles fine, and runs without complaint, but the window did not disable.
I also tried:
window->setEnabled(false);
....
window->setEnabled(true);
...that doesn't seem to do anything either.
I tried this too:
QList<QWidget*> list = window->findChildren<QWidget *>();
foreach(QWidget *qw, list)
{
qw->setEnabled(false);
}
....
QList<QWidget*> list = window->findChildren<QWidget *>();
foreach(QWidget *qw, list)
{
qw->setEnabled(true);
}
..also does nothing.
Based on Qt documentation (http://doc.qt.io/archives/qt-4.8/qwidget.html#enabled-prop):
Disabling a widget implicitly disables all its children. Enabling
respectively enables all child widgets unless they have been
explicitly disabled.
So your snippets are essentially doing same thing in different ways so that doesn't seem to be a problem and modality of dialog shouldn't have any effect on this as well. How are you loading / saving the data? If you are doing it in e.g. click slot then you are basically blocking the UI event loop which means that UI doesn't have cycles to react to your changes. If you want to isolate UI from background action so it will properly react even that you are doing heavy lifting in the background and you should consider using QRunnable or QTread to offload the work away from UI thread.

How to Move through Application's Screens

How to implement a callback interface to go for example from Main Menu screen to start period screen when pressing start period button and return to Main menu screen when pressing main menu button in start period screen.
Main Menu screen image
Start period screen image
You can use DataFX and its Flow mechanism. If you prefer not to use an external library you can do one of the following:
Use a single controller for UI, have a reference to all your UI "screens" which are essentially some type of containers, like BorderPane, VBox, etc. When button start is clicked, you change the root of the Scene to period UI. Having same controller class means all references are in the same place, so when go back button is pressed, you change the root back to main UI.
If your code is rather big, you can use controllers for each UI, but then you will need to implement some basic global event system. When a change in the Scene's root is required you fire an event, say CHANGE_SCENE, and attach some info, like the reference to the UI root. Once the event is caught, change the Scene root to the one you received by the event system.

Is there a way to configure popup menu delay for a QToolButton with popupMode == DelayedPopup?

I'm creating an app with a history like in a web browser: back and forward buttons with a popup menu which is showed on press and hold. The DelayedPopup mode was created exactly for my scenario and it kind of works.
The problem is that the delay used to detect a hold is too short. While I have no trouble with back-forward buttons in, say, Google Chrome, in my app popup menus are popping up regulary when I intend just a simple click.
I suppose setting the delay to a larger value will solve the issue but I can't find a way to do this. The doc says
The default delay is 600 ms; you can adjust it with setPopupDelay()
but it's clearly wrong or outdated info because there is no setPopupDelay in sight.
Any suggestions?
Upd: Though increased delay considerably helped the popup menu still gets shown from time to time. I think there is a bug in Qt.
setPopupDelay was used by Qt 3. Now you have to create your own style by subclassing QStyle or one of its subclasses, and re-implementing the QStyle::styleHint method.
int MyStyle::styleHint(StyleHint hint, const QStyleOption *option, const QWidget *widget, QStyleHintReturn *returnData) const
{
if (hint == QStyle::SH_ToolButton_PopupDelay)
return 1200;
return QStyle::styleHint(hint, option, widget, returnData);
}

Qt: how can i put my main window in the background while im processing with window in forground?

Im using Qt framework , and i looking for the best method to show the user im processing something
how in Qt i can:
put the main window in the background and pop up window to the foreground with
for example " processing " massage
until its done processing the " processing " window will close and the main window returns to the foreground .
Use QProgressDialog. It is designed for that kind of use. You can use the QProgressDialog as a modal dialog thus preventing any user interaction to your main window. QProgressDialog also gives you an easy way to present the progress of your processing and an optional pushbutton to abort processing.
Edit:
QProgressBar can be used in two states: progressing in steps or just showing busy state.
QProgressDialog's progress bar cannot be used showing busy state because that would require setting QProgressDialog's min and max values to 0, which immediately closes the progress dialog. However, you can give the QProgressDialog a new progress bar using setBar()-function. Then you can set this progress bar's min, max and value to 0 and then getting the busy look.
QProgressDialog progressDialog("Processing...", "Abort", 0, INT_MAX, this);
QProgressBar* bar = new QProgressBar(&progressDialog);
bar->setRange(0, 0);
bar->setValue(0);
progress.setBar(bar);
progressDialog.setMinimumWidth(350);
progressDialog.setMinimumDuration(1000);
progressDialog.setWindowModality(Qt::WindowModal);
progressDialog.setValue(0);
// Do your time consuming processing here, but remember to change
// the progress dialog's value a few times per second.
// That will keep the busy indicator moving.
progressDialog.setValue(progressDialog.value() + 1);
// And check if the user has cancelled the processing
if (progressDialog.wasCanceled())
break or return or whatever necessary
// When your processing is done, close the dialog.
progressDialog.close();
You can try that:
In the function that call the pop-up just hide the main window once the process pop-up displayed.
Connect the end processing signal to the main window slot Show(). If you have not predefined signal for that, create one and emit it.
emit NameOfSignal;
Hope that helps
Edit:
For disabling the main window use setDisabled instead of hide and setEnabled instead of show.
You can give your "Processing"-window the Qt::WindowStaysOnTopHint to make it stay on top of your disabled main window.
If it's not to fancy for you, you can blur your main window using QGraphicsBlurEffect while the processing window is on top. That way the user gets the impression of the main window to be not accessable until your processing is done.

how to keep a nativewindow on top

I need to keep a NativeWindow I am creating on top of the main window of the application.
Currently I am using alwaysInFront = true, which is not limited to the windows in the application. I can successfully synchronize the minimize/restore/move/resize actions, so the top window behaves appropriately in those cases. Even though using this option has the drawback that if I alt-tab to other application the window goes on top of the other application.
Because of the above I am trying to get it to work without using the alwaysInFront. I have tried using orderInFrontOf and orderToFront, which gets it in place but when I click an area in the main window the top one becomes hidden i.e. air makes it the top one.
I have tried capturing activate/deactivate events but it only happens on the first click, so on the second click the top window becomes hidden again. I also tried making the top window active when the main one becomes active, but that causes the main one to loose focus and I can't click on anything.
Ps. I am doing this to improve the behavior of a HTMLOverlay I am using - see Flex Air HTMLLoader blank pop up window when flash content is loaded
Listening for Event.DEACTIVATE and calling event.preventDefault() should work. Not sure if that is what you have tried, but I have an app where that does the trick.
I ended up turning on/off the alwaysInFront option based on whether the main window or the top window were active i.e. if none where active I turned it off. This was additionally to what I mentioned in the question.
That way when the user switches to another application, the window doesn't go on top of the other apps. I still would prefer a solution where I don't have to use the alwaysInFront option, or even better an alternate solution to the flex loading flash in external sites issue I linked to above.
Ps. I will try to check with the owner of the HTMLOverlay to submit a patch (its an improvement, although its tied to an app that doesn't open extra windows when opening the overlay).
Update: I have committed the changes to the HTMLOverlay.
I'm trying to do something very similar. In an AIR application, I have one large full screen window which is essentially the "desktop". I always want this window to stay behind all other windows in my app. There are, however, some items on the "desktop" window that need to be clickable.
There appears to be no clean way to force a window to maintain its position in the window ordering.
What I've settled on so far, which isn't perfect, is to make all other windows in my app use the alwaysOnTop property but bind this to a global var (ugh) that I maintain to track the overall application level active/inactive state. This way, when I switch to another app, my windows don't float above the all other app windows - they correctly move behind as expected.
Then, I have a regular (alwaysOnTop=false) window that is fully transparent as an "overlay" to the desktop window on which I can place various interactive controls. This window is OK to come forward since it's transparent and my other windows are alwaysOnTop.
Finally, and crucially, I install three event listeners on the "desktop" window as follows:
protected function onApplicationComplete(event:Event):void
{
this.addEventListener(MouseEvent.MOUSE_DOWN, onClickHandler, true,1000,true);
this.addEventListener(MouseEvent.CLICK, onClickHandler, true,1000,true);
this.nativeWindow.addEventListener(Event.ACTIVATE, onActivateWindow,false,-1);
}
protected function onActivateWindow(event:Event):void
{
trace("sent via activate to back");
orderInBackOf(bigTransparentWindow);
}
protected function onClickHandler(event:MouseEvent):void
{
trace("sent via click to back");
orderInBackOf(bigTransparentWindow);
}
I'm not entirely happy with all this since there is still some occasionally noticeable flicker of objects in the overlay window - it appears that the "Desktop" window gets ordered in front of it, an update of some sort happens, and then it gets forced behind again.
Any better solutions welcome!

Resources