(EZGUI) Popup-Menus in Common Controls

Started by Theo Gottwald, March 01, 2008, 09:03:55 PM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

Theo Gottwald

Today I had the effect, that a PopUp-Menu was only called after a RMB-DC (=Right Mouse Button Double-Click).

Here is my sollution. This is an Example in EZGUI-Code, but anyone not familiar with it will also understand it, as the biggest difference is just the "EZ_" infront of anything. Please note that this is a Issue of common controls like Listviews and Treeviews and not an specific EZGUI topic.


' Here are the Listview Events
SUB WF_LISTVIEW1_Events( MyID&, CMsg&, CVal&, Cancel&)
          CASE %EZ_Selected
          CASE %EZ_Focus
          CASE %EZ_RButtonUp ' Doesn't work, the Listview does not generate this Event
          CASE ELSE

SUB WF_LISTVIEW1_Notify(BYVAL CVal&, Cancel&)
   ' The term "WF" will identify the Form and will be internally computed to the Form-Windows-handle, this is EZGUI specific.
    U_LV_Notify "WF",CVal&, Cancel&

' Here we get the Right Mouse button Click
    LOCAL T01 AS PointAPI
     LOCAL hCtrl&, ID&, NCode&  , NM AS LONG PTR, X&, Y&
     EZ_GetNotify CVal&, hCtrl&, ID&, NCode&
     SELECT CASE AS LONG NCode&   ' Notification Code
         CASE -5   ' this is NM_RCLICK
            GetCursorPos(T01) ' This is the way to get the Mouse Position in Screen coordinates
           ' Here comes the EZGUI PopUp-Menu
           R01=EZ_SetMouseXY(T03,T04) ' this will decode the Hi- and Loword of the X- and Y-Position
         '  Please note the "S" at the end, this will make the Menu appear in Screen coordinate
         EZ_DoPopupMenu S01, R01, 9000, S02, "S" 

' And  this is the Message Loop for the Form itself.
' This is where we get the Menu-Press.
SUB WF_Events(CID&, CMsg&, CVal&, Cancel&)
          CASE %EZ_Window
               SELECT CASE AS LONG CMsg&
                    CASE %EZ_Loading
                    CASE %EZ_Loaded
                        U_WF_Loaded() ' This is User-Code
                    CASE %EZ_Size
                         EZ_ResizeRTForm "WF" 
                    CASE %EZ_Close
                         EZ_FreeRTForm "WF"
                    CASE ELSE
               END SELECT
           ' Popup_menu-Items
           CASE 9000:IF CMsg& = %EZ_Click THEN U_WF_B3(0) ' Copy
           CASE 9001:IF CMsg& = %EZ_Click THEN U_WF_B4()  ' Delete
           CASE 9002:IF CMsg& = %EZ_Click THEN U_WF_B2() ' Cut       
           CASE ELSE
END SUB       

And while I already solved the problem my way, Chris came up with another sollution. The following text is from a mail I just got:

QuoteHello Theo,

I solved the problem and posted working code in the forum.



The problem was quite simple. Popup menus don't work right with the common controls (ie. treeview, listview) when created during a mouse down event.

They must be created during a mouse UP event. This is a quirk in Windows and has nothing to do with EZGUI as far as I can tell. The trouble was getting the right button up event. This can't be done trhough subclassing because the common controls are somehow preventing the generation of this message.
It can be down though through WM_NOTIFY and I demonstrate how to do it.

The code in my posted example should work exactly the same for the listview control.

I am posting this here, as this is stuff good to now.

Chris Boss


I just posted the solution on my forums.

The problem is twofold.

First, displaying popup menus during a mouse DOWN event, appears to give Windows trouble.
It is best to display popup menus on the mouse UP event. This prevents any lockups of dialogs
displayed right after the popup disappears. If you right click in most apps, you will notice a popup
menu does not appear until after the mouse up action.

Next, trapping the right mouse up event can't be done trhough simple subclassing with some of
the common controls (ie. listview, treeview). The reason is that when the mouse button goes down
the control does something strange which prevents the occurance of the WM_RBUTTONUP message
being sent to the controls window procedure. You only get WM_RBUTTONUP after a double click.

Fortunately, the common controls generate the NM_RCLICK notification event through WM_NOTIFY.
This gives you the mouse button up event for the right button, but some controls don't pass the
mouse position via NM_RCLICK. This means you need to trap the mouse position some other way.

In the code I posted on the forum, I subclass the control and trap the WM_RBUTTONDOWN event
and store the lparam value (mouse position) in a global variable and then in the NM_RCLICK event, I
use that value for displaying the popup menu. The coordinates though will have to be converted from
the control client arrea to the forms client area for displaying the popup menu.

The moral of the store is, display right click popup menus in the UP mouse action and not down.

Dominic Mitchell

You are actually doing too much work.

By the way, why would you want to display a context menu on mouse down?  That is so unusual that I
can't remember ever seeing a control or app that did that.

To correct place to display a context menu is during the WM_CONTEXTMENU message which is generated
after the mouse button is released.  There are times when doing it on button up is the only solution
to prevent the control from displaying its own menu, but that is a different story.

In Phoenix, you just drop a ContextMenu control on a form or container and then associate it with the
listview control via the PopupMenu property of the listview control.  Phoenix will then generate
the following code to handle the displaying of the context menu.

      ' Display the context menu associated with the window
      IF GetDlgCtrlID(wParam) = %IDC_FORM1_LISTVIEW1 THEN
        lMsgResult = phnxContextMenu(hWnd, wParam, lParam, ghInstance, %IDR_FORM1_POPUPMENU1, dwFlags)
      END IF

What this code shows, is that you do not need to subclass/superclass or respond to notifications from
a control in order to display a context menu for that control.
The one common exception to this is the Edit control and its built-in menu which predates Windows 95
and the introduction of the WM_CONTEXTMENU message.
Dominic Mitchell
Phoenix Visual Designer

Theo Gottwald

Dominic, I know that PopUp-Menüs in Phoenix are much easier, and thats one of the reasons why I wrote Chris that I believe that this part of EZGUI is not yet streamlined.
But to be honest, in my opinion there are other things which are easier in EZGUI (extensive library with wrapper for controls and Drag and Drop support) and thats why I decided to use it for this project. Especially Drag and Drop would have been more complicated for me using Phoenix because I had to find out how to do it myself first by studying a lot of example code (which is available, from you at several place). But this takes time.

Thats why I say "All the tools in my toolbox have their usage and will be taken out when their time comes".
If I had to do things with Splitterbars - for example - Phoenix would be the tool of choice.

Dominic Mitchell

The reason for my post was to point out that you guys were ignoring the message that was introduced in Windows to handle context menus.  Why fumble around with mouse messages and control events when all you need is WM_CONTEXTMENU?
Dominic Mitchell
Phoenix Visual Designer

Chris Boss

WM_CONTEXTMENU is an excellent way of trapping the right click for popup menus.
The controls forward this message to the parent form.

The thing is that one would have to figure out what control is sending the message (by its handle) and then forward an event to the appropriate routine in the EZGUI app.

That is not difficult, since getWindow long would get the control ID and EZGUI can provide the forms name from its handle.

Theo Gottwald

You both may not want to hear that, but for me the Designer from Dominic and the library from Chris would be a very good RAD-Team :-).