I don't really know how to formulate my question this time...
I have my application with a QDialog as a main window.
The application is getting different values like temperature, humidity and so on from a remote machine.
For development I added a group box with different widgets to simulate these values. I have different limits for throwing warnings and alarms to the user.
For example if temperature rises over 30°C then I open a QMessageBox with the request time (the application does polling at the remote machine) and the current temperature. So this is updated each request cycle.
I use the show() method to bring up the message box which keeps my application running in background. The problem now is: the focus is at the message box and nothing in my main window/ QDialog can be clicked until the message box is not accepted/ has finished.
And that's my problem: in simulation mode I want to play around with different temperature values which I can adjust by slider in the main window. How can I access these widgets/ make the message box somehow "not-blocking"?
Best regards,
Matthias
What you're experiencing is called "modality" of a window. By default, a QMessageBox is "application modal". This means that input to all other application windows is blocked.
To change the modality, use setWindowModality() with a value from Qt::WindowModality just before you call show(). In your case:
box->setWindowModality(Qt::NonModal);
box->show();
Indeed you have a modal message box which is the way QMessageBox is intended to work - ie the user is to be alerted and the ui is protected from further interaction until the user has registered the message, closed the message box and (if necessary) taken any action required in response to the message.
Now if you set the message box modality to Qt::NonModal, (remember to assign it to a variable that won't go out of scope when your application continues after popping up the messagebox) you'll be able to interact with the ui even while the message box is displayed., which I have to say is 'unusual'. If I understand your requirement you will already have the message box up - then while this is still up, you'll then want to play around with different temp values in the main window - to what effect? Until another message dialog box is produced? The message box is going to have to be discarded at some point.
Not only that, but if you show a non modal message box and then interact with the main window, you're quite likely to just have the message box disappear behind the main window, out of sight anyway.
I'd suggest that message boxes are generally treated as intended - transient, temporary modal alert boxes only and that perhaps you require a clearly visible live report/status area in your main window rather than utilizing a non-modal QMessageBox.
Hope this helps
Regards
Roger
Related
I am trying to implement a scenario where two Qt windows will be placed side by side and they will be kind of sticky to each other. By dragging one of them, the other also gets dragged. Even when doing an alt-tab they should behave like a single window.
Any help or pointer will be extremely helpful.
-Soumya
What you describe sounds like it's a good fit for a "docking" scenario. You're probably most familiar with docking from toolbars; where you can either float a toolbar on its own or stick it to any edge of an app's window. But Qt has a more generalized mechanism:
http://doc.qt.io/qt-5/qtwidgets-mainwindows-dockwidgets-example.html
http://doc.qt.io/qt-5/qdockwidget.html
It won't be a case where multiple top level windows are moved around in sync with their own title bars and such. The top-level windows will be merged into a single containing window when they need to get "sticky". But IMO this is more elegant for almost any situation, and provides the properties you seem to be seeking.
Install a event filter on the tracked window with QObject::installEventFilter() and filter on QEvent::Move
You can then change the position of tracking window whenever your filter is called with that event type.
I found a way to keep two windows anchored: when the user moves a window, the other follows, keeping its relative position to the moved one.
It is a bit of a hack, because it assumes that the event QEvent::NonClientAreaMouseButtonPress is sent when the user left clicks on the title bar, holding it pressed while he moves the window, and releasing it at the end, so that QEvent::NonClientAreaMouseButtonRelease is sent.
The idea is to use the QWidget::moveEvent event handler of each window to update the geometry of the other, using QWidget::setGeometry.
But the documentation states that:
Calling setGeometry() inside resizeEvent() or moveEvent() can lead to infinite recursion.
So I needed to prevent the moveEvent handler of the windows which was not moved directly by the user, to update the geometry of the other.
I achieved this with result via QObject::installEventFilter, intercepting the summentioned events.
When the user clicks on the title bar of WindowOne to start a move operation, WindowOne::eventFilter catches its QEvent::NonClientAreaMouseButtonPress and sets the public attribute WindowTwo::skipevent_two to true.
While the user is moving WindowOne, WindowTwo::moveEvent is called upon the setGeometry operation, performed on WindowTwo from WindowOne::moveEvent.
WindowTwo::moveEvent checks WindowTwo::skipevent_two, and if it is true, returns without performing a setGeometry operation on WindowOne which would cause infinite recursion.
As soon as the user releases the left mouse button, ending the window move operation, WindowOne::eventFilter catches QEvent::NonClientAreaMouseButtonRelease and sets back the public attribute WindowTwo::skipevent_two to false.
The same actions are performed if the user clicks the titlebar of WindowTwo, this time causing WindowOne::skipevent_one attribute to be set to true and preventing WindowOne::moveEvent to perform any setGeometry operation on WindowTwo.
I believe this solution is far from being clean and usable. Some problems:
I am not sure when and why QEvent::NonClientAreaMouseButtonRelease and QEvent::NonClientAreaMouseButtonRelease are dispatched, apart from the case considered above.
When/if one window is resized without user interaction or without the proper mouse clicks from the user, probably everything will go the infinite recursion way.
There is no guarantee that those mouse events will be dispatched the same way in the future.
Free space for more...
Proof of concept:
https://github.com/Shub77/DockedWindows
Functionnaly :
On one of my components of my application, I have an editing/lock system. When a user starts editing, he locks the file so other users cannot edit it.
Problem scenario : When the user activates "edition mode" and leaves screen, I would like to show a alert with two options : save changes, or discard changes.
There are different ways to exit screen :
There is a List on the left side containing other possible editabel data. A click changes the data in my component.
There is a menubar on top leading to other screens.
The edition component is embedded in a Tab navigator. When changing tabs, the alert has to show.
Closing browser.
Do I have to catch all of these events and plug at all those places?
Is there any kind of focusout mecanism?
The answer to the first question is: YES.
You need to watch all possible exit events that could harm the currently edited data.
Well, the problem is now how to manage this properly. Using an MVC framework you would trigger the appropriate commands from your components:
CHANGE_LIST_ITEM (new item)
CHANGE_TAB (new tab)
CHANGE_SCREEN (new screen)
Each command then checks if the currently edited tab has been saved or not. If not, it displays the Alert. Else, if there are no changes, it allows the list, the screen chooser and the tab bar to continue.
So your components (list, screens, tabs) need to implement some kind of rollback or preventDefault mechanism. Generally, changing their state must be allowed by a central validator (in MVC the command).
In the case of the list: I would suggest that the list is not selectable by mouse click but only programmatically. You set a listener on the list item click event. If the command allows setting of a new item it will notify the list. In MVC usually by sending an async message that gets received by the list's mediator. [[And even more correct: The command would set some model properties (e.g. currentListItem) and the model than sends an async message.]]
Edit: For the browser close event, you need to call a JavaScript expert.
I have a problem with Qt modeless dialog in Solaris 8/10 machine using CDE (Common Desktop Environment).
The dialog serve as drawing panel/popup that required user to choose the tools from main application before proceeding to draw on it. The problem is whenever user click on main application toolbar, then the dialog will goes behind the main application.
Notice that this is the behavior pertaining to CDE only, Open Windows enviroment or Solaris Java environment don't cause this issue.
My question is how can I make it always on top of its parent (main application)?
I've tried to pass in WX11BypassWM flag to the dialog, to by pass window manager, but then the border and frame is gone which cause the dialog to not drag/move-able.
Update 1:
With regard to Andy's answer:
I've tried Qt::WStyle_StaysOnTop, but it doesn't work.
I tried also to combine:
WX11BypassWM | WStyle_StaysOnTop | WStyle_Title
and other combinationa of WStyle_DialogBorder, WType_TopLevel etc, it only stays on top if WX11BypassWM is passed in.
But whenever WX11BypassWM is passed in, the dialog shown up will not have border nor the tittle bar.
Which means it's a unmove-able tittle-less dialog.
Update 2:
Since I can't find a solution for this issue, for the time being, I resolve it by resizing and reposition the main application and the modeless dialog to be side by side.
This at least will let user navigate in both interface.
Anyone if has a better suggestion then let me know.
I'm not sure I understood your question, but, wouldn't it be possible to use :
Found in QtAssistant :
enum Qt::WindowType
flags Qt::WindowFlags
Qt::WindowStaysOnTopHint :
"Informs the window system that the window should stay on top of all other windows."
I hope it helps a bit !
I have an AIR app about half way done right now. I was informed by the client today that he does not want a tab to show up in his task bar. I already have this in place for new windows by making them lightweight. I do not know how to make the main window lightweight though. If there is not a way, is there a work around, like not not having a main window and just opening lightweight windows, don't know how that could be done either though? Anyone know how to do this?
Thanks!
Check this doc out. -- Yes, you can do this. In short, you have to hide the initial window - then display your application in a lightweight window.
Also - do note: On a Mac - the behavior is different. By convention, a window is not shown in the 'task bar' when it is displayed. When it is minimized it is in the bar. To hide the application when minimized on a Mac - you have to make the window 'invisible' instead of minimizing it. The doc mentioned above gives further details.
The key part of the doc for your case:
On the Windows operating system,
windows created with the types utility
or lightweight do not appear on the
taskbar. Invisible windows do not
appear on the taskbar, either.
Because the initial window is
necessarily of type, normal, in order
to create an application without any
windows appearing in the taskbar, you
must either close the inital window or
leave it invisible.
To close all
windows in your application without
terminating the application, set the
autoExit property of the
NativeApplication object to false
before closing the last window. To
simply prevent the intial window from
ever becoming visible, add
false to the
element of the
application descriptor file (and do
not set the visible property to true
or call the activate() method of the
window).
In new windows opened by the
application, set the type property of
the NativeWindowInitOption object
passed to the window constructor to
NativeWindowType.UTILITY or
NativeWindowType.LIGHTWEIGHT.
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!