Force a menu to close

Windows specific forum
RichardL
Enthusiast
Enthusiast
Posts: 532
Joined: Sat Sep 11, 2004 11:54 am
Location: UK

Force a menu to close

Post 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
User avatar
Bisonte
Addict
Addict
Posts: 1320
Joined: Tue Oct 09, 2007 2:15 am

Re: Force a menu to close

Post by Bisonte »

maybe simulate a left mouseclick to the actual coursorpos ?
PureBasic 6.21 (Windows x64) | Windows 11 Pro | AsRock B850 Steel Legend Wifi | R7 9800x3D | 64GB RAM | RTX 5080 | ThermaltakeView 270 TG ARGB | build by vannicom​​
English is not my native language... (I often use DeepL.)
PB
PureBasic Expert
PureBasic Expert
Posts: 7581
Joined: Fri Apr 25, 2003 5:24 pm

Re: Force a menu to close

Post by PB »

I compile using 5.31 (x86) on Win 7 Ultimate (64-bit).
"PureBasic won't be object oriented, period" - Fred.
RichardL
Enthusiast
Enthusiast
Posts: 532
Joined: Sat Sep 11, 2004 11:54 am
Location: UK

Re: Force a menu to close

Post 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! :oops:
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. :(
Last edited by RichardL on Thu Feb 06, 2014 12:42 pm, edited 1 time in total.
PB
PureBasic Expert
PureBasic Expert
Posts: 7581
Joined: Fri Apr 25, 2003 5:24 pm

Re: Force a menu to close

Post 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. :shock:
I compile using 5.31 (x86) on Win 7 Ultimate (64-bit).
"PureBasic won't be object oriented, period" - Fred.
RichardL
Enthusiast
Enthusiast
Posts: 532
Joined: Sat Sep 11, 2004 11:54 am
Location: UK

Re: Force a menu to close

Post by RichardL »

@PB
Did you try my version of your code..?
RichardL
PB
PureBasic Expert
PureBasic Expert
Posts: 7581
Joined: Fri Apr 25, 2003 5:24 pm

Re: Force a menu to close

Post 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? :shock:
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
I compile using 5.31 (x86) on Win 7 Ultimate (64-bit).
"PureBasic won't be object oriented, period" - Fred.
User avatar
Shardik
Addict
Addict
Posts: 2069
Joined: Thu Apr 21, 2005 2:38 pm
Location: Germany

Re: Force a menu to close

Post 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
RichardL
Enthusiast
Enthusiast
Posts: 532
Joined: Sat Sep 11, 2004 11:54 am
Location: UK

Re: Force a menu to close

Post by RichardL »

@PB
Oh dear, we seem to be going around in circles... :D :(

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.... :D
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.
User avatar
Shardik
Addict
Addict
Posts: 2069
Joined: Thu Apr 21, 2005 2:38 pm
Location: Germany

Re: Force a menu to close

Post by Shardik »

RichardL wrote:Almost perfect.... :D
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

Code: Select all

If lParam = MenuID(0)
by

Code: Select all

If wParam & $FF = 0
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 ! :wink:
RASHAD
PureBasic Expert
PureBasic Expert
Posts: 4997
Joined: Sun Apr 12, 2009 6:27 am

Re: Force a menu to close

Post 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)
Egypt my love
User avatar
Shardik
Addict
Addict
Posts: 2069
Joined: Thu Apr 21, 2005 2:38 pm
Location: Germany

Re: Force a menu to close

Post by Shardik »

Good one RASHAD... :wink:

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
PB
PureBasic Expert
PureBasic Expert
Posts: 7581
Joined: Fri Apr 25, 2003 5:24 pm

Re: Force a menu to close

Post 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?
I compile using 5.31 (x86) on Win 7 Ultimate (64-bit).
"PureBasic won't be object oriented, period" - Fred.
User avatar
netmaestro
PureBasic Bullfrog
PureBasic Bullfrog
Posts: 8452
Joined: Wed Jul 06, 2005 5:42 am
Location: Fort Nelson, BC, Canada

Re: Force a menu to close

Post 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
BERESHEIT
Post Reply