Announcement

Collapse
No announcement yet.

Popup menu mouse cursor

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • Popup menu mouse cursor

    When I subclass the richedit control and load a popup menu under the WM_CONTEXTMENU handler, the cursor remains in the editor shape (I-beam) and MOUSEPTR appears to have no effect.

    The same menu works in a similar context in the dialog with the correct pointer shape.

    Any suggestions most welcome.

    Compileable code is PBWin 8.04
    Code:
    ' Popup Menu mouse cursor problem
    ' Chris Holbrook 18 Mar 2008
    ' why does the mouse cursor look like I-beam not pointer
    #COMPILE EXE
    #DIM ALL
    
    #INCLUDE "WIN32API.INC"
    #INCLUDE "RICHEDIT.INC"
    
    %IDD_DIALOG1   = 101
    %IDC_RICHEDIT1 = 102
    
    '---------------------------------------------------------------------------
    FUNCTION subClassEditProc(BYVAL hWnd AS DWORD, BYVAL wMsg AS DWORD, BYVAL wParm AS DWORD, BYVAL lParm AS DWORD) AS LONG
        LOCAL p AS PointAPI
        LOCAL hpopup, MenuChoice AS LONG
        LOCAL smsg AS STRING
        STATIC dwOrigEditProc AS DWORD
        STATIC InfoDlg                  AS DWORD' handle of Ctrl-G info dialog
        '
        IF hWnd = 0 THEN           ' initial message from parent
            dwOrigEditProc = wparm
            FUNCTION = 1
            EXIT FUNCTION
        END IF
    
        SELECT CASE wMsg
            CASE %WM_CONTEXTMENU
                hPopup = CreatePopupMenu
                CALL InsertMenu(hPopup, 0, %MF_BYCOMMAND              , 1, "&Apples")
                CALL InsertMenu(hPopup, 0, %MF_BYCOMMAND              , 2, "&Oranges")
                CALL InsertMenu(hPopup, 0, %MF_BYCOMMAND              , 3, "&Done")
                CALL InsertMenu(hPopup, 0, %MF_BYCOMMAND              , 4, "&Cancel")
                MOUSEPTR 1 ' pointer shape
                CALL GetCursorPos(BYREF p)
                MenuChoice = TrackPopupMenuEx(hPopup, %MF_ENABLED OR %MF_BYCOMMAND OR %TPM_RETURNCMD, p.x, p.y, _
                             hWnd, BYVAL %NULL)
                CALL DestroyMenu(hPopup)
                SELECT CASE menuchoice
                        '
                END SELECT
                MOUSEPTR 3 'I-beam shape
        END SELECT
        FUNCTION = CallWindowProc(dwOrigEditProc, hWnd, wMsg, wParm, lParm)
        
    END FUNCTION
    '---------------------------------------------------------------------------
    CALLBACK FUNCTION ShowDIALOG1Proc()
        LOCAL dwOrigEditProc AS DWORD
        SELECT CASE AS LONG CBMSG
            CASE %WM_INITDIALOG
                dwOrigEditProc = SetWindowLong(getdlgitem(CBHNDL, %IDC_RICHEDIT1), _
                                 %GWL_WNDPROC, CODEPTR(subClassEditProc)) 'subclass
                ' call the subclassed control directly to tell it what it's original WndProc is
                subClassEditProc 0, 0, dwOrigEditProc, 0
        END SELECT
    END FUNCTION
    '----------------------------------------------------
    FUNCTION ShowDIALOG1(BYVAL hParent AS DWORD) AS LONG
        LOCAL lRslt AS LONG
        LOCAL hDlg  AS DWORD
    
        DIALOG NEW hParent, "Mouse Cursor Question 18-MAR-2008", 70, 70, 201, 121, %WS_POPUP OR %WS_BORDER OR %WS_DLGFRAME OR _
            %WS_SYSMENU OR %WS_CLIPSIBLINGS OR %WS_VISIBLE OR %DS_MODALFRAME OR %DS_3DLOOK OR %DS_NOFAILCREATE OR %DS_SETFONT, _
            %WS_EX_CONTROLPARENT OR %WS_EX_LEFT OR %WS_EX_LTRREADING OR %WS_EX_RIGHTSCROLLBAR, TO hDlg
        CONTROL ADD "RichEdit50W", hDlg, %IDC_RICHEDIT1, "RichEdit1", 5, 5, 190, 110, %WS_CHILD OR %WS_VISIBLE OR %WS_TABSTOP OR _
            %WS_VSCROLL OR %WS_HSCROLL OR %ES_LEFT OR %ES_MULTILINE OR %ES_AUTOVSCROLL OR %ES_AUTOHSCROLL OR %ES_WANTRETURN, _
            %WS_EX_CLIENTEDGE OR %WS_EX_LEFT OR %WS_EX_LTRREADING OR %WS_EX_RIGHTSCROLLBAR
    
        DIALOG SHOW MODAL hDlg, CALL ShowDIALOG1Proc TO lRslt
        FUNCTION = lRslt
    END FUNCTION
    
    '=================================================================
    FUNCTION PBMAIN()
        LOCAL hlib AS LONG
        LOCAL s AS STRING
        hLib = LoadLibrary("Msftedit.dll") 'Riched32.dll")
        IF hLib = 0 THEN
           s = "File 'Riched20.dll' required"
           MSGBOX s, %MB_ICONWARNING, "File not Found": EXIT FUNCTION
        END IF
    
        ShowDIALOG1 %HWND_DESKTOP
        FreeLibrary hLib
    
    END FUNCTION

  • #2
    Not real sure why the RichEdit control is doing that, but you could use this variation to make it work:

    Code:
    ' Popup Menu mouse cursor problem
    ' Chris Holbrook 18 Mar 2008
    ' why does the mouse cursor look like I-beam not pointer
    #COMPILE EXE
    #DIM ALL
    
    #INCLUDE "WIN32API.INC"
    #INCLUDE "RICHEDIT.INC"
    
    %IDD_DIALOG1   = 101
    %IDC_RICHEDIT1 = 102
    
    '---------------------------------------------------------------------------
    FUNCTION subClassEditProc(BYVAL hWnd AS LONG, BYVAL wMsg AS LONG, BYVAL wParm AS LONG, BYVAL lParm AS LONG) AS LONG
        LOCAL p AS PointAPI
        LOCAL hpopup, MenuChoice AS LONG
        LOCAL smsg AS STRING
        STATIC dwOrigEditProc AS DWORD
        STATIC InfoDlg                  AS DWORD' handle of Ctrl-G info dialog
        '
        IF hWnd = 0 THEN           ' initial message from parent
            dwOrigEditProc = wparm
            FUNCTION = 1
            EXIT FUNCTION
        END IF
    
        SELECT CASE wMsg
            CASE %WM_SETCURSOR
                IF GetWindowLong(hWnd, %GWL_USERDATA) = 1 THEN
                    MOUSEPTR 1
                    FUNCTION = 1
                    EXIT FUNCTION
                END IF
            CASE %WM_CONTEXTMENU
                hPopup = CreatePopupMenu
                CALL InsertMenu(hPopup, 0, %MF_BYCOMMAND              , 1, "&Apples")
                CALL InsertMenu(hPopup, 0, %MF_BYCOMMAND              , 2, "&Oranges")
                CALL InsertMenu(hPopup, 0, %MF_BYCOMMAND              , 3, "&Done")
                CALL InsertMenu(hPopup, 0, %MF_BYCOMMAND              , 4, "&Cancel")
                p.x = LOWRD(lParm)
                p.y = HIWRD(lParm)
                SetWindowLong hWnd, %GWL_USERDATA, 1
                MenuChoice = TrackPopupMenuEx(hPopup, %MF_ENABLED OR %MF_BYCOMMAND OR %TPM_RETURNCMD, p.x, p.y, _
                             hWnd, BYVAL %NULL)
                SetWindowLong hWnd, %GWL_USERDATA, 0
                CALL DestroyMenu(hPopup)
                SELECT CASE menuchoice
                        '
                END SELECT
    
                'MOUSEPTR 3 'I-beam shape
        END SELECT
        FUNCTION = CallWindowProc(dwOrigEditProc, hWnd, wMsg, wParm, lParm)
    
    END FUNCTION
    '---------------------------------------------------------------------------
    CALLBACK FUNCTION ShowDIALOG1Proc()
        LOCAL dwOrigEditProc AS DWORD
        SELECT CASE AS LONG CBMSG
            CASE %WM_INITDIALOG
                dwOrigEditProc = SetWindowLong(getdlgitem(CBHNDL, %IDC_RICHEDIT1), _
                                 %GWL_WNDPROC, CODEPTR(subClassEditProc)) 'subclass
                ' call the subclassed control directly to tell it what it's original WndProc is
                subClassEditProc 0, 0, dwOrigEditProc, 0
        END SELECT
    END FUNCTION
    '----------------------------------------------------
    FUNCTION ShowDIALOG1(BYVAL hParent AS DWORD) AS LONG
        LOCAL lRslt AS LONG
        LOCAL hDlg  AS DWORD
    
        DIALOG NEW hParent, "Mouse Cursor Question 18-MAR-2008", 70, 70, 201, 121, %WS_POPUP OR %WS_BORDER OR %WS_DLGFRAME OR _
            %WS_SYSMENU OR %WS_CLIPSIBLINGS OR %WS_VISIBLE OR %DS_MODALFRAME OR %DS_3DLOOK OR %DS_NOFAILCREATE OR %DS_SETFONT, _
            %WS_EX_CONTROLPARENT OR %WS_EX_LEFT OR %WS_EX_LTRREADING OR %WS_EX_RIGHTSCROLLBAR, TO hDlg
        CONTROL ADD "RichEdit50W", hDlg, %IDC_RICHEDIT1, "RichEdit1", 5, 5, 190, 110, %WS_CHILD OR %WS_VISIBLE OR %WS_TABSTOP OR _
            %WS_VSCROLL OR %WS_HSCROLL OR %ES_LEFT OR %ES_MULTILINE OR %ES_AUTOVSCROLL OR %ES_AUTOHSCROLL OR %ES_WANTRETURN, _
            %WS_EX_CLIENTEDGE OR %WS_EX_LEFT OR %WS_EX_LTRREADING OR %WS_EX_RIGHTSCROLLBAR
    
        DIALOG SHOW MODAL hDlg, CALL ShowDIALOG1Proc TO lRslt
        FUNCTION = lRslt
    END FUNCTION
    
    '=================================================================
    FUNCTION PBMAIN()
        LOCAL hlib AS LONG
        LOCAL s AS STRING
        hLib = LoadLibrary("Msftedit.dll") 'Riched32.dll")
        IF hLib = 0 THEN
           s = "File 'Riched20.dll' required"
           MSGBOX s, %MB_ICONWARNING, "File not Found": EXIT FUNCTION
        END IF
    
        ShowDIALOG1 %HWND_DESKTOP
        FreeLibrary hLib
    
    END FUNCTION
    Adam Drake
    Drake Software

    Comment


    • #3
      I was about ready to post another solution at the same time that Adam posted his. I'm intrigued with the way he did it.

      Adam, how did you know to SetWindowLong with %GWL_USERDATA? What is that doing with just a constant of one? I thought %GWL_USERDATA was used to pass a dword variable that would then be used in some manner.

      Comment


      • #4
        I imagine I picked it up from the forum at some point in the past, however, per the MSDN documentation, %GWL_USERDATA's intended use is as follows:

        %GWL_USERDATA - Sets the user data associated with the window. This data is intended for use by the application that created the window. Its value is initially zero.
        It is a place to store a long value for your use. It could be anything in the range of a long integer, and you as the window creator are the only on that modifies it. So, since it starts at '0', if I set it to '1', as soon as the next WM_SETCURSOR message gets sent to the RichEdit control, it will know to use MOUSEPTR 3.
        Adam Drake
        Drake Software

        Comment


        • #5
          Originally posted by Adam J. Drake View Post
          It is a place to store a long value for your use.
          Very neat, in other words it's a static dword. I've tidied the callback function up a bit as shown and removed the more confusing bits. BTW Charles, what was your solution?

          Code:
          '---------------------------------------------------------------------------
          FUNCTION subClassEditProc(BYVAL hWnd AS DWORD, BYVAL wMsg AS DWORD, BYVAL wParm AS DWORD, BYVAL lParm AS DWORD) AS LONG
              LOCAL hpopup, MenuChoice AS LONG
              STATIC dwOrigEditProc AS DWORD
              STATIC cursorstate    AS DWORD
              '
              IF hWnd = 0 THEN           ' initial message from parent
                  dwOrigEditProc = wparm
                  FUNCTION = 1
                  EXIT FUNCTION
              END IF
          
              SELECT CASE wMsg
                  CASE %WM_SETCURSOR
                      IF cursorstate = 1 THEN
                          MOUSEPTR 1
                          FUNCTION = 1
                          EXIT FUNCTION
                      END IF
                  CASE %WM_CONTEXTMENU
                      hPopup = CreatePopupMenu
                      CALL InsertMenu(hPopup, 0, %MF_BYCOMMAND              , 1, "&Apples")
                      CALL InsertMenu(hPopup, 0, %MF_BYCOMMAND              , 2, "&Oranges")
                      CALL InsertMenu(hPopup, 0, %MF_BYCOMMAND              , 3, "&Done")
                      CALL InsertMenu(hPopup, 0, %MF_BYCOMMAND              , 4, "&Cancel")
                      cursorstate = 1
                      MenuChoice = TrackPopupMenuEx(hPopup, _
                                   %MF_ENABLED OR %MF_BYCOMMAND OR %TPM_RETURNCMD, _
                                   LOWRD(lparm), HIWRD(lparm), _
                                   hWnd, BYVAL %NULL)
                      cursorstate = 0
                      CALL DestroyMenu(hPopup)
                      SELECT CASE menuchoice
                              '
                      END SELECT
              END SELECT
              FUNCTION = CallWindowProc(dwOrigEditProc, hWnd, wMsg, wParm, lParm)
              
          END FUNCTION

          Comment


          • #6
            Thanks, Adam. Stupid me... I didn't notice your use of %WM_SETCURSOR

            Here was my solution:
            Code:
            ' Popup Menu mouse cursor problem
            ' Chris Holbrook 18 Mar 2008
            ' why does the mouse cursor look like I-beam not pointer
            #COMPILE EXE
            #DIM ALL
            
            #INCLUDE "WIN32API.INC"
            #INCLUDE "RICHEDIT.INC"
            
            %IDD_DIALOG1   = 101
            %IDC_RICHEDIT1 = 102
            GLOBAL hDlg, hPopup AS LONG
            
            '---------------------------------------------------------------------------
            FUNCTION subClassEditProc(BYVAL hWnd AS DWORD, BYVAL wMsg AS DWORD, BYVAL wParm AS DWORD, BYVAL lParm AS DWORD) AS LONG
                LOCAL p AS PointAPI
                'LOCAL hpopup, MenuChoice AS LONG
                LOCAL MenuChoice AS LONG
                LOCAL smsg AS STRING
                STATIC dwOrigEditProc AS DWORD
                STATIC InfoDlg                  AS DWORD' handle of Ctrl-G info dialog
                '
                IF hWnd = 0 THEN           ' initial message from parent
                    dwOrigEditProc = wparm
                    FUNCTION = 1
                    EXIT FUNCTION
                END IF
            
                SELECT CASE wMsg
                     CASE %WM_RBUTTONDOWN
                        p.x = LOWRD(lParm): p.y = HIWRD(lParm)
                        ClientToScreen hWnd, p
                        MenuChoice = TrackPopupMenuEx(hPopup, 0, p.x, p.y, hDlg, BYVAL %NULL)
                        CALL DestroyMenu(hPopup)
                      
            '        CASE %WM_CONTEXTMENU 
            '            hPopup = CreatePopupMenu
            '            CALL InsertMenu(hPopup, 0, %MF_BYCOMMAND OR %MF_STRING, 1, "&Apples")
            '            CALL InsertMenu(hPopup, 0, %MF_BYCOMMAND OR %MF_STRING, 2, "&Oranges")
            '            CALL InsertMenu(hPopup, 0, %MF_BYCOMMAND OR %MF_STRING, 3, "&Done")
            '            CALL InsertMenu(hPopup, 0, %MF_BYCOMMAND OR %MF_STRING, 4, "&Cancel")
            '            MOUSEPTR 1 ' pointer shape
            '            CALL GetCursorPos(BYREF p)
            '            MenuChoice = TrackPopupMenuEx(hPopup, %MF_ENABLED OR %MF_BYCOMMAND OR %TPM_RETURNCMD, p.x, p.y, _
            '                         hWnd, BYVAL %NULL)
            '            CALL DestroyMenu(hPopup)
            '            SELECT CASE menuchoice
            '                    '
            '            END SELECT
            '            MOUSEPTR 3 'I-beam shape
                END SELECT
                FUNCTION = CallWindowProc(dwOrigEditProc, hWnd, wMsg, wParm, lParm)
                
            END FUNCTION
            '---------------------------------------------------------------------------
            CALLBACK FUNCTION ShowDIALOG1Proc()
                LOCAL dwOrigEditProc AS DWORD
                SELECT CASE AS LONG CBMSG
                    CASE %WM_INITDIALOG
                        hPopup = CreatePopupMenu
                        CALL InsertMenu(hPopup, 0, %MF_BYCOMMAND OR %MF_STRING, 1, "&Apples")
                        CALL InsertMenu(hPopup, 0, %MF_BYCOMMAND OR %MF_STRING, 2, "&Oranges")
                        CALL InsertMenu(hPopup, 0, %MF_BYCOMMAND OR %MF_STRING, 3, "&Done")
                        CALL InsertMenu(hPopup, 0, %MF_BYCOMMAND OR %MF_STRING, 4, "&Cancel")
                        dwOrigEditProc = SetWindowLong(getdlgitem(CBHNDL, %IDC_RICHEDIT1), _
                                         %GWL_WNDPROC, CODEPTR(subClassEditProc)) 'subclass
                        ' call the subclassed control directly to tell it what it's original WndProc is
                        subClassEditProc 0, 0, dwOrigEditProc, 0
                END SELECT
            END FUNCTION
            '----------------------------------------------------
            FUNCTION ShowDIALOG1(BYVAL hParent AS DWORD) AS LONG
                LOCAL lRslt AS LONG
                'LOCAL hDlg  AS DWORD
            
                DIALOG NEW hParent, "Mouse Cursor Question 18-MAR-2008", 70, 70, 201, 121, %WS_POPUP OR %WS_BORDER OR %WS_DLGFRAME OR _
                    %WS_SYSMENU OR %WS_CLIPSIBLINGS OR %WS_VISIBLE OR %DS_MODALFRAME OR %DS_3DLOOK OR %DS_NOFAILCREATE OR %DS_SETFONT, _
                    %WS_EX_CONTROLPARENT OR %WS_EX_LEFT OR %WS_EX_LTRREADING OR %WS_EX_RIGHTSCROLLBAR, TO hDlg
                CONTROL ADD "RichEdit50W", hDlg, %IDC_RICHEDIT1, "RichEdit1", 5, 5, 190, 110, %WS_CHILD OR %WS_VISIBLE OR %WS_TABSTOP OR _
                    %WS_VSCROLL OR %WS_HSCROLL OR %ES_LEFT OR %ES_MULTILINE OR %ES_AUTOVSCROLL OR %ES_AUTOHSCROLL OR %ES_WANTRETURN, _
                    %WS_EX_CLIENTEDGE OR %WS_EX_LEFT OR %WS_EX_LTRREADING OR %WS_EX_RIGHTSCROLLBAR
            
                DIALOG SHOW MODAL hDlg, CALL ShowDIALOG1Proc TO lRslt
                FUNCTION = lRslt
            END FUNCTION
            
            '=================================================================
            FUNCTION PBMAIN()
                LOCAL hlib AS LONG
                LOCAL s AS STRING
                hLib = LoadLibrary("Msftedit.dll") 'Riched32.dll")
                IF hLib = 0 THEN
                   s = "File 'Riched20.dll' required"
                   MSGBOX s, %MB_ICONWARNING, "File not Found": EXIT FUNCTION
                END IF
            
                ShowDIALOG1 %HWND_DESKTOP
                FreeLibrary hLib
            
            END FUNCTION

            Comment


            • #7
              Top marks Charles because you are using only one message and no statics. Putting menu creation in the dialog callback is better too, but the DestroyMenu had better go there too. The menu handle can be passed in the initial call to the subclassproc.

              I see that the key to it is to put the menu over the dialog not the RichEdit control. Why solve a problem when you can avoid it?

              Comment


              • #8
                Placing this in your dlg proc works just fine:

                Code:
                        Case %WM_CONTEXTMENU
                
                    Local hpopup, MenuChoice As Long
                    Local p As PointAPI
                
                            hPopup = CreatePopupMenu
                            Call InsertMenu(hPopup, 0, %MF_BYCOMMAND              , 1, "&Apples")
                            Call InsertMenu(hPopup, 0, %MF_BYCOMMAND              , 2, "&Oranges")
                            Call InsertMenu(hPopup, 0, %MF_BYCOMMAND              , 3, "&Done")
                            Call InsertMenu(hPopup, 0, %MF_BYCOMMAND              , 4, "&Cancel")
                '            MousePtr 1 ' pointer shape
                            Call GetCursorPos(ByRef p)
                            MenuChoice = TrackPopupMenuEx(hPopup, %MF_ENABLED Or %MF_BYCOMMAND Or %TPM_RETURNCMD, p.x, p.y, _
                                         CbHndl, ByVal %Null)
                            Call DestroyMenu(hPopup)
                            Select Case menuchoice
                                    '
                            End Select
                 '           MousePtr 3 'I-beam shape
                hellobasic

                Comment

                Working...
                X