We have an application that runs both on Windows (using pure WIN32) and Mac OS X. One of the new features we are implementing is iOS style popup windows (see this for a sample image).
The main idea is:
The user clicks a button.
A window pops up with an arrow pointing at the button.
The user uses whatever controls are in the popup (text fields, buttons, sliders, etc...).
When the user clicks elsewhere (or does anything to make another window active), the popup goes away.
My initial attempt at implementing this was to use a window with the WS_POPUP style (and WS_EX_TOOLWINDOW and a few others). This gave me a window in which to place controls, and I could listen for the WM_ACTIVATE message to know when to hide the window. However, this has two main problems:
When the popup window is shown, it steals focus from the main window (causing visible changes to the main window's title bar).
Mouse clicks in the main window are ignored until the popup is hidden. Ie, if the user clicks on button A to open popup A, then clicks on button B, popup A should go away and popup B should be shown. Instead, popup A goes away, but the mouse click on button B is ignored.
As far as I can tell, the only way to fix #1 is to make use WS_CHILD instead of WS_POPUP. Creating the popup window without focus seems to work, but as soon as the user interacts with one of the controls the popup window is given focus.
I'm thinking that WS_CHILD might also solve #2 as well (although that's just an educated guess at this point).
So my questions are:
Will using WS_CHILD instead of WS_POPUP solve both problems?
If I use WS_CHILD, will the window be able to be moved outside of the parent's client area, or will it be clipped (the idea being that this is a floating window that may or may not be fully contained in the parents client area).
Are there any other ways to accomplish what I need (I've explored custom drawing menus or tooltips, since both seem to have a lot of the characteristics I need, but putting arbitrary controls in either was pretty much a dead end).
I was able to fix issue #1 by handling the WM_NCACTIVATE message to force the parent to look active when the popup window is visible.
I'm still having problems with issue #2. I've played around with the WM_MOUSEACTIVATE message - according to what I've found online and on MSDN, returning MA_ACTIVATE should tell Windows to "click-through" to the button. Messing around with other Windows programs, this behavior is sometimes seen and sometimes not. Any ideas on getting this working?
I'm not really sure how that will help - I really just need inactive buttons to respond to mouse click events (not saying it won't help, I just don't see it...).
When the popup window is shown, it steals focus from the main window (causing visible changes to the main window's title bar).
Mouse clicks in the main window are ignored until the popup is hidden. Ie, if the user clicks on button A to open popup A, then clicks on button B, popup A should go away and popup B should be shown. Instead, popup A goes away, but the mouse click on button B is ignored.
This undoubtedly indicates that the created popup is a modal dialog. And you get the behavior precisely how you program it.
As far as I can tell, the only way to fix #1 is to make use WS_CHILD instead of WS_POPUP.
Wrong. Modeless dialog would not prevent main window from activation.
Creating the popup window without focus seems to work, but as soon as the user interacts with one of the controls the popup window is given focus.
Again, this is normal behavior. Any action on a control gives it the focus. You have to intentionally transfer the one to another window, if required. Though I can't see why would you do that.
Are there any other ways to accomplish what I need
Capturing mouse (as Victor already suggested) would let you process clicks outside the window.
This undoubtedly indicates that the created popup is a modal dialog. And you get the behavior precisely how you program it.
From my understanding, I'm not creating a modal dialog (it's actually not a dialog at all, it's created with CreateWindowEx). There is only a single message loop and control is returned to me right away after displaying the popup window.
Originally Posted by Igor Vartanov
Wrong. Modeless dialog would not prevent main window from activation.
The popup window doesn't prevent the main window from activating - however, I want it to look like the main window is always active, even when the user is interacting with the popup window (the idea being that the popup window acts like a child window, even though it doesn't have to be fully contained within the parent). I don't think there's anything wrong with the implementation, other than I want behavior that is different than the standard.
Originally Posted by Igor Vartanov
Again, this is normal behavior. Any action on a control gives it the focus. You have to intentionally transfer the one to another window, if required. Though I can't see why would you do that.
I'm ok with the controls in the popup window receiving focus, I just want the main window to look active all of the time. And by handling the WM_NCACTIVATE message (among others) I was able to achieve this.
Originally Posted by Igor Vartanov
Capturing mouse (as Victor already suggested) would let you process clicks outside the window.
This issue I have with this is that I don't want to capture events outside of the window - mouse events should be sent to the window that the mouse is over. However, when the popup window is displayed, if the user clicks on the main window (outside and behind the popup), in addition to the popup window closing and the main window becoming active, the main window should also process that mouse click. So for example, if the user clicks on a button in the main window when the popup is active, the popup should close and the button should behave as if it was clicked.
From my understanding, I'm not creating a modal dialog (it's actually not a dialog at all, it's created with CreateWindowEx). There is only a single message loop and control is returned to me right away after displaying the popup window.
Why would you not use a dialog for this? If you want to place any kind of control on the popup window, using a dialog seems the easiest way to me.
Originally Posted by Runt888
This issue I have with this is that I don't want to capture events outside of the window - mouse events should be sent to the window that the mouse is over. However, when the popup window is displayed, if the user clicks on the main window (outside and behind the popup), in addition to the popup window closing and the main window becoming active, the main window should also process that mouse click. So for example, if the user clicks on a button in the main window when the popup is active, the popup should close and the button should behave as if it was clicked.
If your popup is a modeless window and you did not capture the input (using SetCapture), then this should be the normal behavior. My guess is that you are doing something to prevent the mouse click from being handled normally. Hard to say without an example, of course.
Cheers, D Drmmr
Please put [code][/code] tags around your code to preserve indentation and make it more readable.
As long as man ascribes to himself what is merely a posibility, he will not work for the attainment of it. - P. D. Ouspensky
Why would you not use a dialog for this? If you want to place any kind of control on the popup window, using a dialog seems the easiest way to me.
We have a cross platform framework that allows us to create views once and use them on both Windows and OS X.
Originally Posted by D_Drmmr
If your popup is a modeless window and you did not capture the input (using SetCapture), then this should be the normal behavior. My guess is that you are doing something to prevent the mouse click from being handled normally. Hard to say without an example, of course.
This is very possible - it's good to know that this should work, and now I just need to figure out what is causing it to not work.
From my understanding, I'm not creating a modal dialog (it's actually not a dialog at all, it's created with CreateWindowEx). There is only a single message loop and control is returned to me right away after displaying the popup window.
Then you need to explain "Mouse clicks in the main window are ignored until the popup is hidden", as this totally contradicts to what you just said.
The popup window doesn't prevent the main window from activating - however, I want it to look like the main window is always active, even when the user is interacting with the popup window (the idea being that the popup window acts like a child window, even though it doesn't have to be fully contained within the parent). I don't think there's anything wrong with the implementation, other than I want behavior that is different than the standard.
Okay, then it's wrong with your wanting. Window manager behavior differs from what you want. Child window is clipped by parent's client area. To prevent this clipping the popup must be an overlapping window, and overlapping window activation deactivates any other window on the desktop.
I'm ok with the controls in the popup window receiving focus, I just want the main window to look active all of the time. And by handling the WM_NCACTIVATE message (among others) I was able to achieve this.
Good to hear that, though I hardly understand the details.
This issue I have with this is that I don't want to capture events outside of the window - mouse events should be sent to the window that the mouse is over. However, when the popup window is displayed, if the user clicks on the main window (outside and behind the popup), in addition to the popup window closing and the main window becoming active, the main window should also process that mouse click. So for example, if the user clicks on a button in the main window when the popup is active, the popup should close and the button should behave as if it was clicked.
Then you need to handle popup window deactivation event where you make the window to close.
Then you need to explain "Mouse clicks in the main window are ignored until the popup is hidden", as this totally contradicts to what you just said.
I apologize, I wasn't very specific. I should have said "mouse clicks in the main window cause the main window to become active (which in turn hides the popup window), but otherwise they are not being handled (ie, clicking on a button in the main window while a popup is visible will hide the popup, but no WM_COMMAND event is received from the button)."
Thanks for the example! I apologize for taking so long to get back to you - I was pulled on to a different project temporarily.
Your sample does exhibit the behavior I'm looking for, so it looks like I need to figure out what I'm doing that is preventing the mouse clicks from being handled.
* The Best Reasons to Target Windows 8
Learn some of the best reasons why you should seriously consider bringing your Android mobile development expertise to bear on the Windows 8 platform.