Page 1 of 1
Force a menu to close
Posted: Thu Feb 06, 2014 10:44 am
by RichardL
Good morning,
I would like to force a standard Windows menu to close when the mouse cursor leaves it, instead of waiting for the user to click somewhere else. So far I have detected the mouse has left the menu but cannot find out how to close the menu.
Code: Select all
Procedure WinCallback(hwnd, uMsg, wParam, lParam)
Select uMsg
Case #WM_MENUSELECT
If wParam & $FFFF = #MF_DISABLED And lParam = MenuID(MenuWm)
; Close the menu
EndIf
etc
etc
Would someone kindly point me in the right direction?
Thanks
RichardL
Re: Force a menu to close
Posted: Thu Feb 06, 2014 10:49 am
by Bisonte
maybe simulate a left mouseclick to the actual coursorpos ?
Re: Force a menu to close
Posted: Thu Feb 06, 2014 11:31 am
by PB
Re: Force a menu to close
Posted: Thu Feb 06, 2014 11:53 am
by RichardL
Gentlemen,
Thanks for your replies.
1. Whoops! I found that my code triggers when the menu opens as well as when it closes... so its NBG at present!
2. I tried PB's approach and it behaves similarly.
Code: Select all
Procedure WindowCallback(hwnd,uMsg,wParam,lParam)
Select uMsg
Case #WM_ENTERIDLE
GetCursorPos_(cpt.POINT)
If WindowFromPoint_(PeekQ(cpt))=hwnd
EndMenu_()
EndIf
EndSelect
ProcedureReturn #PB_ProcessPureBasicEvents
EndProcedure
OpenWindow(0,0,0,320,240,"Select menu then move mouse right",#PB_Window_SystemMenu|#PB_Window_ScreenCentered)
ButtonGadget(1,20,20,200,50,"Hello")
CreateMenu(0,WindowID(0))
MenuTitle("Things")
MenuItem(1,"Cut")
MenuItem(2,"Copy")
MenuItem(3,"Paste")
MenuBar()
OpenSubMenu("Options")
MenuItem(4,"Window...")
MenuItem(5,"Gadget...")
CloseSubMenu()
MenuBar()
MenuItem(6,"Quit")
SetWindowCallback(@WindowCallback())
Repeat
EventID = WaitWindowEvent()
Until EventID = #PB_Event_CloseWindow
Any more suggestions would be welcomed!
RichardL
Edited: Button gadget added to show another difficulty.

Re: Force a menu to close
Posted: Thu Feb 06, 2014 11:58 am
by PB
I don't get it. You said...
> I would like to force a standard Windows menu to close when the mouse cursor leaves it
...and the link I provided does just that.

Re: Force a menu to close
Posted: Thu Feb 06, 2014 12:22 pm
by RichardL
@PB
Did you try my version of your code..?
RichardL
Re: Force a menu to close
Posted: Thu Feb 06, 2014 1:56 pm
by PB
> Did you try my version of your code..?
Yes, but it doesn't make the menu appear. Is that your point?
On the other hand, the menu appears with the code I linked,
and that menu auto-closes when the mouse moves off it...
exactly like you requested in your first post.
> Button gadget added to show another difficulty
What exactly is the difficulty with the button?

It doesn't even do anything. It's just for decoration.
Code quoted below as you posted it:
Code: Select all
Procedure WindowCallback(hwnd,uMsg,wParam,lParam)
Select uMsg
Case #WM_ENTERIDLE
GetCursorPos_(cpt.POINT)
If WindowFromPoint_(PeekQ(cpt))=hwnd
EndMenu_()
EndIf
EndSelect
ProcedureReturn #PB_ProcessPureBasicEvents
EndProcedure
OpenWindow(0,0,0,320,240,"Select menu then move mouse right",#PB_Window_SystemMenu|#PB_Window_ScreenCentered)
ButtonGadget(1,20,20,200,50,"Hello")
CreateMenu(0,WindowID(0))
MenuTitle("Things")
MenuItem(1,"Cut")
MenuItem(2,"Copy")
MenuItem(3,"Paste")
MenuBar()
OpenSubMenu("Options")
MenuItem(4,"Window...")
MenuItem(5,"Gadget...")
CloseSubMenu()
MenuBar()
MenuItem(6,"Quit")
SetWindowCallback(@WindowCallback())
Repeat
EventID = WaitWindowEvent()
Until EventID = #PB_Event_CloseWindow
Re: Force a menu to close
Posted: Thu Feb 06, 2014 3:08 pm
by Shardik
RichardL,
please try this one:
Code: Select all
Procedure WindowCallback(hWnd, Msg, wParam, lParam)
Static MenuIsOpen
Select Msg
Case #WM_MENUSELECT
If lParam = MenuID(0)
If MenuIsOpen
MenuIsOpen = #False
EndMenu_()
EndIf
EndIf
Case #WM_ENTERIDLE
GetCursorPos_(cpt.POINT)
If WindowFromPoint_(cpt\x | (cpt\y << 32)) = hwnd
If MenuIsOpen
MenuIsOpen = #False
EndMenu_()
EndIf
Else
MenuIsOpen = #True
EndIf
EndSelect
ProcedureReturn #PB_ProcessPureBasicEvents
EndProcedure
OpenWindow(0,100,100,320,240,"Select menu then move mouse right")
ButtonGadget(1,20,20,200,50,"Hello")
CreateMenu(0,WindowID(0))
MenuTitle("Things")
MenuItem(1,"Cut")
MenuItem(2,"Copy")
MenuItem(3,"Paste")
MenuBar()
OpenSubMenu("Options")
MenuItem(4,"Window...")
MenuItem(5,"Gadget...")
CloseSubMenu()
MenuBar()
MenuItem(6,"Quit")
SetWindowCallback(@WindowCallback())
Repeat
Until WaitWindowEvent() = #PB_Event_CloseWindow
Re: Force a menu to close
Posted: Thu Feb 06, 2014 3:50 pm
by RichardL
@PB
Oh dear, we seem to be going around in circles...
My need is for a standard menu, attached to a menu bar, to close when the mouse pointer goes away from the menu.
Your original solution addresses the same need but with a popup menu.
It does not work if there is a gadget under the popup menu; as is almost inevitably the case .
Code: Select all
Procedure WindowCallback(hwnd,uMsg,wParam,lParam)
Select uMsg
Case #WM_ENTERIDLE
GetCursorPos_(cpt.POINT)
If WindowFromPoint_(PeekQ(cpt))=hwnd
EndMenu_()
EndIf
EndSelect
ProcedureReturn #PB_ProcessPureBasicEvents
EndProcedure
OpenWindow(0,0,0,320,240,"Right-click!",#PB_Window_SystemMenu|#PB_Window_ScreenCentered)
ButtonGadget(1,20,20,200,200,"Test")
CreatePopupMenu(0)
MenuItem(1,"Cut")
MenuItem(2,"Copy")
MenuItem(3,"Paste")
MenuBar()
OpenSubMenu("Options")
MenuItem(4,"Window...")
MenuItem(5,"Gadget...")
CloseSubMenu()
MenuBar()
MenuItem(6,"Quit")
SetWindowCallback(@WindowCallback())
Repeat
EventID = WaitWindowEvent()
If EventID = #WM_RBUTTONDOWN
DisplayPopupMenu(0,WindowID(0))
EndIf
Until EventID = #PB_Event_CloseWindow
Neither does it work with a standard menu attached to a menu bar:
Code: Select all
Procedure WindowCallback(hwnd,uMsg,wParam,lParam)
Select uMsg
Case #WM_ENTERIDLE
GetCursorPos_(cpt.POINT)
If WindowFromPoint_(PeekQ(cpt))=hwnd
EndMenu_()
EndIf
EndSelect
ProcedureReturn #PB_ProcessPureBasicEvents
EndProcedure
OpenWindow(0,0,0,320,260,"Select menu then move mouse right",#PB_Window_SystemMenu|#PB_Window_ScreenCentered)
ButtonGadget(1,20,20,200,200,"Hello")
CreateMenu(0,WindowID(0))
MenuTitle("Things")
MenuItem(1,"Cut")
MenuItem(2,"Copy")
MenuItem(3,"Paste")
MenuBar()
OpenSubMenu("Options")
MenuItem(4,"Window...")
MenuItem(5,"Gadget...")
CloseSubMenu()
MenuBar()
MenuItem(6,"Quit")
SetWindowCallback(@WindowCallback())
Repeat
EventID = WaitWindowEvent()
Until EventID = #PB_Event_CloseWindow
In this case the callback is being triggered repeatedly and the menu cannot deploy.
@Shardik
Almost perfect....
The only remaining difficulty is that if a user exits with the conventional left mouse button it takes two attempts to get the menu to drop down again.
Re: Force a menu to close
Posted: Thu Feb 06, 2014 4:17 pm
by Shardik
RichardL wrote:Almost perfect....

The only remaining difficulty is that if a user exits with the conventional left mouse button it takes two attempts to get the menu to drop down again.
You may solve this problem by replacing
by
But there exists a 2nd problem with my code example: when leaving Options -> Window... by moving the cursor up onto the button the menu won't be closed... - but I am on it !

Re: Force a menu to close
Posted: Thu Feb 06, 2014 4:35 pm
by RASHAD
Good one Shardik
Code: Select all
If WindowFromPoint_(cpt\x | (cpt\y << 32)) = hWnd Or WindowFromPoint_(cpt\x | (cpt\y << 32)) = GadgetID(1)
Re: Force a menu to close
Posted: Thu Feb 06, 2014 4:55 pm
by Shardik
Good one RASHAD...
But I hope to have found a more general solution (no need to put the fixed GadgetID(1) into the Callback):
Code: Select all
Procedure WindowCallback(hWnd, Msg, wParam, lParam)
Static MenuIsOpen
Static LastMenuHandle.I
Select Msg
Case #WM_MENUSELECT
If wParam & $FF = 0
If MenuIsOpen
MenuIsOpen = #False
EndMenu_()
EndIf
Else
If LastMenuHandle <> 0 And LastMenuHandle <> lParam And wParam & $00100000
MenuIsOpen = #False
EndMenu_()
Else
LastMenuHandle = lParam
EndIf
EndIf
Case #WM_ENTERIDLE
GetCursorPos_(cpt.POINT)
If WindowFromPoint_(cpt\x | (cpt\y << 32)) = hwnd
If MenuIsOpen
MenuIsOpen = #False
EndMenu_()
EndIf
Else
MenuIsOpen = #True
EndIf
EndSelect
ProcedureReturn #PB_ProcessPureBasicEvents
EndProcedure
OpenWindow(0,100,100,320,240,"Select menu then move mouse right")
ButtonGadget(1,20,20,200,50,"Hello")
CreateMenu(0,WindowID(0))
MenuTitle("Things")
MenuItem(1,"Cut")
MenuItem(2,"Copy")
MenuItem(3,"Paste")
MenuBar()
OpenSubMenu("Options")
MenuItem(4,"Window...")
MenuItem(5,"Gadget...")
CloseSubMenu()
MenuBar()
MenuItem(6,"Quit")
SetWindowCallback(@WindowCallback())
Repeat
Until WaitWindowEvent() = #PB_Event_CloseWindow
Re: Force a menu to close
Posted: Fri Feb 07, 2014 3:11 am
by PB
Okay, I was focussed on PopupMenus instead of standard Menus.
Now I see what you're talking about.

I didn't realize there was
so much of a difference in them.
So, let's try a simpler approach. In your original post, you said that
you can detect when the mouse has left the menu, and all you need
now is a way to close it. This is the code you posted:
Code: Select all
If wParam & $FFFF = #MF_DISABLED And lParam = MenuID(MenuWm)
; Close the menu
EndIf
Therefore, I would recommend just sending an Escape keypress to close the menu:
Code: Select all
If wParam & $FFFF = #MF_DISABLED And lParam = MenuID(MenuWm)
; Close the menu
keybd_event_(#VK_ESCAPE,0,0,0) : keybd_event_(#VK_ESCAPE,0,#KEYEVENTF_KEYUP,0)
EndIf
Does that do the job?
Re: Force a menu to close
Posted: Fri Feb 07, 2014 10:29 pm
by netmaestro
Code: Select all
Procedure WindowCallback(hwnd,uMsg,wParam,lParam)
Select uMsg
Case #WM_ENTERIDLE
GetCursorPos_(cpt.POINT)
cn$=Space(255)
GetClassName_(WindowFromPoint_(PeekQ(cpt)), @cn$, 255)
If cn$ <> "#32768"
EndMenu_()
EndIf
EndSelect
ProcedureReturn #PB_ProcessPureBasicEvents
EndProcedure
OpenWindow(0,0,0,320,240,"Right-click!",#PB_Window_SystemMenu|#PB_Window_ScreenCentered)
ButtonGadget(1,20,20,200,200,"Test")
CreatePopupMenu(0)
MenuItem(1,"Cut")
MenuItem(2,"Copy")
MenuItem(3,"Paste")
MenuBar()
OpenSubMenu("Options")
MenuItem(4,"Window...")
MenuItem(5,"Gadget...")
CloseSubMenu()
MenuBar()
MenuItem(6,"Quit")
SetWindowCallback(@WindowCallback())
Repeat
EventID = WaitWindowEvent()
If EventID = #WM_RBUTTONDOWN
DisplayPopupMenu(0,WindowID(0))
EndIf
Until EventID = #PB_Event_CloseWindow