How to programmatically close wxMenu used as popup menu via `wxWindow::PopupMenu` in wxWidgets? - c++

I have a set of instances of plotting view that's added/removed dynamically according to incoming signals from tcp port from another process.
In each instance, the user can right click to open a popup menu, invoked via wxWindow::PopupMenu.
If the plotting view instance is to got shutted-down dynamically while the popup menu is visible, the view instance window is closed while the popup menu is still floating. Then any GUI action crashes the application.
I've been going through the APIs for wxWidgets to find a way to programmatically close the popup menu in the plotting view destructor, but with no-luck.
I found this forum post suggesting it's an impossible thing to close the popup menu programmatically. But it's too old, so not sure if it's still valid assumption.
Here are the trials that failed till now :
Trying to call SetFocus and SetFocusFromKbd on the plotting view as a way to move focus.
Generating mouse left click event and send it to the popup menu.
Generating a keyboard event and send it to the popup menu.
PlottingView::~PlottingView()
{
cout << "Sending wxMouseEvent to the popup menu" << endl;
wxMouseEvent e(wxEVT_LEFT_UP);
this->GetPopupMenu()->ProcessEvent(e);
wxKeyEvent ke(wxEVT_CHAR);
ke.m_keyCode = WXK_DOWN;
this->GetPopupMenu()->ProcessEvent(ke);
ke.m_keyCode = WXK_RETURN;
this->GetPopupMenu()->ProcessEvent(ke);
// the rest of the destruction
}
So I will appreciate any idea to programmatically close this popup menu.
Platform:
CentOS: 6.7
wxWidgets 2.8.12
G++: 4.3.3
Edit #1
Note: For commenters and answers suggesting upgrading the wxWidgets version, it's a debate in my team for everyday. But the answer is still no.
Most of the trials has failed. But I found a workaround to stop crashing but the popup menu don't close.
The solution was to nullify the following members using their setters, so the menu callback won't access them.
this->GetPopupMenu()->SetInvokingWindow(NULL);
this->GetPopupMenu()->SetEventHandler(NULL);

The best is probably to delay destroying the underlying window until PopupMenu() returns. As it is, your program logic is very convoluted because you're dispatching the event which results in closing of the window from inside PopupMenu() function and this just can't end well, even if you could use wxUIActionSimulator to close the menu (but you definitely should consider upgrading your 15 year old wxWidgets version in any case).

Related

How to detect that a window is currently running a modal dialog? [duplicate]

This question already has answers here:
Detecting modal dialogs in MFC
(4 answers)
Closed 4 years ago.
I have a wizard interface (so a property sheet with property pages).
On one of the pages, I am running a background timer to keep detecting whether a given external thing is true or not (well, I compile a list of attached visible USB security dongles).
But when this page shows a modal dialog box - e.g. a MessageBox, I want to suspend/ignore the timer notifications.
I can do that by simply killing the timer - running the message box - then starting the timer anew. That works perfectly but requires that all calls to MessageBox remember to do this. Not a huge deal, but inelegant.
Now, I could also wrapper MessageBox so that I use a helper wrapper function which does the suspend / resume timer for the caller. That's a valid thought - but it still requires maintenance coders to always remember to call my wrapper function, and this doesn't work well for other modal dialog boxes that might need to be run which also would need to have the suspend/resume timer dance performed.
What I believe is ideal is to leave the timer running, but have the timer handler itself check if we're currently running a modal dialog, and if so, simply ignore the timer notification (the timer will continue to spew notifications in a few moments - and eventually we'll be done with the modal dialog [message box] and we can go ahead and handle the timer notification then).
But what I do not see is a mechanism by which to ask "Am I running a modal dialog right now?"
From the POV of the page's timer handler - it doesn't know if a modal dialog box is in progress or not. IsWindowEnabled() returns true - so at least the standard windows MessageBox() does NOT disable the parent window... which leaves me mildly confused as to how it is locking out button clicks on its parent window (my mind is a sieve these days - maybe the answer is obvious and I'm just getting old ;) )
Anyway - what am I missing? What is a simple test for "Is a modal dialog box running right now in this thread / as a child of this window?"
Thanks for any gentle clues you might have to offer
So, I was asking IsWindowEnabled() from the context of the property page - which is a child window within the wizard dialog.
Changing that to GetParent()->IsWindowEnabled() does return false while running a modal dialog.

Disable all top level window (WS_POPUP) when showing modal dialog

I have the main window, and then the user can "pop up" one of the frames in the application so that it floats rather than being contained in the main window. There are multiple frames that can be popped up so that in a given time there might be three WS_POPUP windows.
The problem is when I want to show the modal dialog, I can only disable one of them using the parameter in the DoModal function. How can I disable all top-level windows using DoModal? I can't simply disable the windows before showing modal and then enable it back because There could multiple chained modal dialog (one modal dialog opens up another modal dialog).
Does the API provide a way to do something like this? I've googled this for two hours and can't find a good enough solution. I'm using a combination of MFC, WTL, and ATL.
Thanks in advance!
As I understand the problem, it is the same like the MFC frame windows work.
In fact only the CFrameWnd of an MFC application gets disabled. On arrival off the WM_ENABLE message (with FALSE) BeginModalState is called and this function just disables it floating "child windows" of the CFrameWnd.
Same again, when EnableWindow (WM_ENABLE arrives with TRUE) is called for CFrameWnd. EndModalState is called and all disabled "child and floating" windows are enabled again.
See the MFC implementation of CFrameWnd::OnEnable, BeginModalState, EndModalSTate in the source code.
So you main window knows it's own popups. Upon launching the true modal dialog, and disabling this parent, it will disable it's floating popups.
The trick is that CDialog::DoModal needs the real parent... if not given in the constructor it guesses the correct one in most cases. For your case it should be necessary that you provide your "main window" as the parent window... same for message boxes...

Programmatically clicking toolbar button in parent of modal window

I have an application that hooks into another application via an API. My application launches a modal window which prevents keypresses to reach the parent as one would expect.
However due to limitations in the API I need to click one of the parents toolbar buttons from time to time (yes it's a kludge).
I wonder if this is possible while still having the modal window of my application active? Is it perhaps possible to send the required command directly into the parent command queue?
Clicking the button programmatically with no modal window should not be a problem, one could go by this link for example: http://forums.codeguru.com/showthread.php?307633-How-to-run-a-very-long-SQL-statement. But I would prefer not having to close my window each time I have to click the button.
Although the fifth answer is what I find interesting as I'm thinking this could make it possible to send the command without having to close my modal window first. Also it feels an ever so small bit less ugly.
First of all, when a modal dialog is shown, it runs its own message pump. So any attempt to fake input messages will land in the modal dialog message pump. Which is no good to you. So, you'd have to send a message rather than fake input.
However, when a modal dialog is shown, its owning windows are disabled. Which means that these windows will not respond to any messages you send. So I guess that means that you could:
Enable the owning top-level window that you hosts the toolbar in question.
Send the message to the toolbar button.
Disable the owning window again.
Not the prettiest way to go about things, but you did ask!

QDialog as Popup does not hide on Mac when clicking out of the main window

I have a basic QDialog with it's WindowFlags set to Qt::Popup so that it appears as a typical popup overlay.
On Windows, everything works great and if you click outside the main window or really anywhere else it goes away. But on Mac OSX, if you click the menu bar at the top or resize the window, the popup just stays where it is. I have absolutely no internal handling of the mouse enter/leave/move/press events for the popup, so the closing of it is not something I'm even handling... it's just automatic on Windows.
Any idea I can get it to close when the main application is no longer the current context on the system?
You may install native event filter and to close active popup dialog (QApplication::activePopupWidget()) when user will click out of main window. See the following answer for information how to install native filter.

"Sticky" MFC popup menu

I currently have some toolbar buttons with a small arrow on the side (TBSTYLE_EX_DRAWDDARROWS) that, when clicked, result in a popup context menu being displayed under the button. This is done by constructing a custom popup menu and calling TrackPopupMenu.
The client now wants to be able to select multiple options from the menu before it closes, so that multiple options can be be modified without the need to re-open the menu and wait for an intermediate redraw between each change.
For example:
User clicks dropdown button
Dropdown menu appears (modal, waits indefinitely for user action)
User clicks some item (e.g., toggle a checkmark)
Timer (e.g., 500ms) starts
If timer expires, the menu is closed and all selected actions are executed.
User clicks another item before the timer expires, go back to 4.
The best I can come up with is to redisplay the menu by calling TrackPopupMenu multiple times. This makes the menu "flicker" when you select an item, and will probably require me to start a thread in order to do the timeouts, which I would rather avoid.
Rather than a menu, put up a dialog box with the options on it. A dialog can easily do all that is required.
A menu that doesn't close when you click it will just seem wrong. A dialog that closes by itself will seem wrong too, but it's probably the least of two evils.
Edit: If there's anything I've learned with Microsoft, it's don't try to fight the default behavior. You're asking for trouble if you do.
If you're building your menu dynamically I can see how automatic sizing can be handy, but it's not hard to do in a dialog either - make the dialog really big and before it becomes visible, enumerate the children and take a union of all their rectangles, then resize to that. Checking the boundaries to make sure they're on-screen is just a few if statements with OffsetRect. Checkboxes are trivial; icons less so, but still not bad.
One additional enhancement that would be easy to add is to dismiss the dialog immediately on a double-click.
Following #Mark Ransom's answer, you should put up a dialog box. But you can make the dialog modeless and make it close itself when you click outside of it (i.e., the dialog loses focus). That way it could behave more like a menu.
Notice that normal menus never go away by themselves, you always have to click somewhere outside the menu (or one of its options) to make it disappear.