Right-click on a ComboBoxGadget

Just starting out? Need help? Post your questions and find answers here.
RobertRioja
User
User
Posts: 86
Joined: Thu May 02, 2019 3:57 am
Location: USA
Contact:

Right-click on a ComboBoxGadget

Post by RobertRioja »

I hope someone can answer this. If I click on a ComboBoxGadget, its list will drop down so I can click on any item. That will trigger the #PB_EventType_Change event. However, I need to right-click on an item and I don't see a way of capturing that event.

Any ideas?

Thanks,
Rob
Axolotl
Addict
Addict
Posts: 861
Joined: Wed Dec 31, 2008 3:36 pm

Re: Right-click on a ComboBoxGadget

Post by Axolotl »

Which OS?

On windows maybe by doing the following:
1. Get the ListBox handle (GetComboBoxInfo),
2. subclass it (SetWindowSubclass)
3. look at WM_RBUTTONDOWN and LB_ITEMFROMPOINT
Just because it worked doesn't mean it works.
PureBasic 6.04 (x86) and <latest stable version and current alpha/beta> (x64) on Windows 11 Home. Now started with Linux (VM: Ubuntu 22.04).
Axolotl
Addict
Addict
Posts: 861
Joined: Wed Dec 31, 2008 3:36 pm

Re: Right-click on a ComboBoxGadget

Post by Axolotl »

Here is an example of right-click on the dropdown-listbox ..... (Windows Only)

Code: Select all

EnableExplicit 

Import "Comctl32.lib"  ;{ <<< from (latest) Comctl32.dll  >>>
  ; use the PureBasic Syntax (Windows API procedures using trailing underscore) 
  ; 
  CompilerIf #PB_Compiler_Processor = #PB_Processor_x64
    SetWindowSubclass_(hWnd, *fnSubclass, uIdSubclass, dwRefData)  As "SetWindowSubclass" 
    GetWindowSubclass_(hWnd, *fnSubclass, uIdSubclass, *dwRefData) As "GetWindowSubclass"
    RemoveWindowSubclass_(hWnd, *fnSubclass, uIdSubclass)          As "RemoveWindowSubclass"
    DefSubclassProc_(hWnd, uMsg, wParam, lParam)                   As "DefSubclassProc"
  CompilerElse
    SetWindowSubclass_(hWnd, *fnSubclass, uIdSubclass, dwRefData)  As "_SetWindowSubclass@16" 
    GetWindowSubclass_(hWnd, *fnSubclass, uIdSubclass, *dwRefData) As "_GetWindowSubclass@16"
    RemoveWindowSubclass_(hWnd, *fnSubclass, uIdSubclass)          As "_RemoveWindowSubclass@12"
    DefSubclassProc_(hWnd, uMsg, wParam, lParam)                   As "_DefSubclassProc@16" 
  CompilerEndIf
EndImport 

; for simplicity's sake, constants (enums are even better)  
#WND_Main = 1 
#GDT_cbbTest = 2 

Structure COMBOBOXINFO 
  cbSize.l        ; DWORD 
  rcItem.RECT     ; RECT  
  rcButton.RECT   ; RECT  
  stateButton.l   ; DWORD 
  hwndCombo.i     ; HWND  
  hwndItem.i      ; HWND  
  hwndList.i      ; HWND  
EndStructure 

#LB_ITEMFROMPOINT = 425 

Procedure SubclassComboboxList(hWnd, uMsg, wParam, lParam, uIdSubclass, dwRefData) 
  Protected index, pt.POINT 

  Select uMsg 
    Case #WM_NCDESTROY                                                         : Debug "WM_NCDESTROY" 
      RemoveWindowSubclass_(hWnd, @SubclassComboboxList(), uIdSubclass) 

    Case #WM_LBUTTONDOWN                                                       : Debug "WM_LBUTTONDOWN" 

    Case #WM_RBUTTONDOWN                                                       : Debug "WM_RBUTTONDOWN" 
      GetCursorPos_(@pt) 
      ScreenToClient_(hWnd, @pt) 
      index = ((pt\y & $FFFF) << 16) + (pt\x + $FFFF) 
      index = SendMessage_(hWnd, #LB_ITEMFROMPOINT, 0, index) 
      If (index >> 16) & $FFFF  ; inside the listbox 
        index & $FFFF                                   : Debug "  index == " + index + "   outside " 
      Else 
        index & $FFFF                                   : Debug "  index == " + index + "   inside " 
      EndIf 

  EndSelect 
  ProcedureReturn DefSubclassProc_(hWnd, uMsg, wParam, lParam) 
EndProcedure

Procedure Main() 
  Protected ii, hList, cbi.COMBOBOXINFO 

  If OpenWindow(#WND_Main, 0, 0, 256, 200, "Something with Combobox ... ", #PB_Window_ScreenCentered|#PB_Window_SystemMenu) 
    StickyWindow(#WND_Main, 1) ; always on top :) 

    ComboBoxGadget(#GDT_cbbTest, 8, 8, 240, 24) 
      For ii = 1 To 9 
        AddGadgetItem(#GDT_cbbTest, -1, "Test Text Item "+ii) 
      Next 
      SetGadgetState(#GDT_cbbTest, 1) 


    cbi\cbSize = SizeOf(COMBOBOXINFO) 
    If GetComboBoxInfo_(GadgetID(#GDT_cbbTest), @cbi)
      hList = cbi\hwndList                                  : Debug "Combobox List hwnd == " + hList 
      SetWindowSubclass_(hList, @SubclassComboboxList(), #GDT_cbbTest, 0)  ; 
    EndIf 

    Repeat
      Select WaitWindowEvent()
        Case #PB_Event_CloseWindow 
          Break ; say good bye. 
      EndSelect
    ForEver
  EndIf 
EndProcedure 

End Main() 
Just because it worked doesn't mean it works.
PureBasic 6.04 (x86) and <latest stable version and current alpha/beta> (x64) on Windows 11 Home. Now started with Linux (VM: Ubuntu 22.04).
RobertRioja
User
User
Posts: 86
Joined: Thu May 02, 2019 3:57 am
Location: USA
Contact:

Re: Right-click on a ComboBoxGadget

Post by RobertRioja »

Hello Axolotl,

Thank you very much. This is exactly what I needed.

Rob
BarryG
Addict
Addict
Posts: 4194
Joined: Thu Apr 18, 2019 8:17 am

Re: Right-click on a ComboBoxGadget

Post by BarryG »

Code: Select all

If OpenWindow(0, 0, 0, 270, 80, "ComboBoxGadget", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)

  ComboBoxGadget(0, 10, 10, 250, 21)
  For a = 1 To 5
    AddGadgetItem(0, -1,"ComboBox item " + Str(a))
  Next
  
  Repeat
  
    ev=WaitWindowEvent()
    
    If ev=#WM_RBUTTONDOWN
      Debug "Right-clicked on "+Str(GetGadgetState(0))
    EndIf
    
  Until ev = #PB_Event_CloseWindow
  
EndIf
Axolotl
Addict
Addict
Posts: 861
Joined: Wed Dec 31, 2008 3:36 pm

Re: Right-click on a ComboBoxGadget

Post by Axolotl »

Works well, with one limitation: If the mouse is outside the list box when clicked, it is not recognized.
Just because it worked doesn't mean it works.
PureBasic 6.04 (x86) and <latest stable version and current alpha/beta> (x64) on Windows 11 Home. Now started with Linux (VM: Ubuntu 22.04).
BarryG
Addict
Addict
Posts: 4194
Joined: Thu Apr 18, 2019 8:17 am

Re: Right-click on a ComboBoxGadget

Post by BarryG »

How is that a limitation? The request is for when the gadget is right-clicked, so if the gadget is not in focus, then no big deal?
RobertRioja
User
User
Posts: 86
Joined: Thu May 02, 2019 3:57 am
Location: USA
Contact:

Re: Right-click on a ComboBoxGadget

Post by RobertRioja »

The real problem is that right-clicking anywhere will trigger the event. I need it to trigger ONLY when an item in the ComboBoxGadget is right-clicked.

Rob
User avatar
mk-soft
Always Here
Always Here
Posts: 6270
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Re: Right-click on a ComboBoxGadget

Post by mk-soft »

Code: Select all

;-TOP by mk-soft

Procedure IsCursorOnGadget(Gadget)
  Protected r1, hWnd, cursor.q, rect.RECT
  hWnd = GadgetID(Gadget)
  GetCursorPos_(@cursor)
  GetClientRect_(hWnd, @rect)
  ClientToScreen_(hWnd, @rect)
  rect\right + rect\left
  rect\bottom + rect\top
  r1 = PtInRect_(@rect, cursor)
  ProcedureReturn r1
EndProcedure

If OpenWindow(0, 0, 0, 270, 80, "ComboBoxGadget", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
  
  ComboBoxGadget(0, 10, 10, 250, 21)
  For a = 1 To 5
    AddGadgetItem(0, -1,"ComboBox item " + Str(a))
  Next
  
  Repeat
    
    ev=WaitWindowEvent()
    
    If ev=#WM_RBUTTONDOWN
      
      If IsCursorOnGadget(0)
        Debug "Right-clicked on "+Str(GetGadgetState(0))
      EndIf
      
    EndIf
    
  Until ev = #PB_Event_CloseWindow
  
EndIf
My Projects ThreadToGUI / OOP-BaseClass / EventDesigner V3
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
RobertRioja
User
User
Posts: 86
Joined: Thu May 02, 2019 3:57 am
Location: USA
Contact:

Re: Right-click on a ComboBoxGadget

Post by RobertRioja »

The problem with the last reply, is that it only works if you right-click on the gadget itself. I need to be able to right-click on an ITEM that is pulled down from the ComboBoxGadget. The IsCursorOnGadget function only looks at the boundaries of the gadget, not the pull down list.

Rob
BarryG
Addict
Addict
Posts: 4194
Joined: Thu Apr 18, 2019 8:17 am

Re: Right-click on a ComboBoxGadget

Post by BarryG »

My code does let you right-click on an item from the drop-down list? It even shows which item number was right-clicked.
Axolotl
Addict
Addict
Posts: 861
Joined: Wed Dec 31, 2008 3:36 pm

Re: Right-click on a ComboBoxGadget

Post by Axolotl »

okay, new try based on my code from above.
Now, after open the Dropdownlist with LeftClick you can use either Left or Right Mouse Click to do the selection.
Easier to show than to describe.
Anyway the result is in the main loop. (I borrowed the #PB_Eventtype_RightClick for that)
Please bear in mind it's a concept only.

Code: Select all

EnableExplicit 

Import "Comctl32.lib"  ;{ <<< from (latest) Comctl32.dll  >>>
  ; use the PureBasic Syntax (Windows API procedures using trailing underscore) 
  ; 
  CompilerIf #PB_Compiler_Processor = #PB_Processor_x64
    SetWindowSubclass_(hWnd, *fnSubclass, uIdSubclass, dwRefData)  As "SetWindowSubclass" 
    GetWindowSubclass_(hWnd, *fnSubclass, uIdSubclass, *dwRefData) As "GetWindowSubclass"
    RemoveWindowSubclass_(hWnd, *fnSubclass, uIdSubclass)          As "RemoveWindowSubclass"
    DefSubclassProc_(hWnd, uMsg, wParam, lParam)                   As "DefSubclassProc"
  CompilerElse
    SetWindowSubclass_(hWnd, *fnSubclass, uIdSubclass, dwRefData)  As "_SetWindowSubclass@16" 
    GetWindowSubclass_(hWnd, *fnSubclass, uIdSubclass, *dwRefData) As "_GetWindowSubclass@16"
    RemoveWindowSubclass_(hWnd, *fnSubclass, uIdSubclass)          As "_RemoveWindowSubclass@12"
    DefSubclassProc_(hWnd, uMsg, wParam, lParam)                   As "_DefSubclassProc@16" 
  CompilerEndIf
EndImport 

; for simplicity's sake, constants (enums are even better)  
#WND_Main = 1 
#GDT_cbbTest = 2 


Structure COMBOBOXINFO 
  cbSize.l        ; DWORD 
  rcItem.RECT     ; RECT  
  rcButton.RECT   ; RECT  
  stateButton.l   ; DWORD 
  hwndCombo.i     ; HWND  
  hwndItem.i      ; HWND  
  hwndList.i      ; HWND  
EndStructure 

#LB_ITEMFROMPOINT = 425 

Procedure SubclassComboboxList(hWnd, uMsg, wParam, lParam, uIdSubclass, dwRefData) 
  Protected index, pt.POINT 

  Select uMsg 
    Case #WM_NCDESTROY                                                         : Debug "WM_NCDESTROY" 
      RemoveWindowSubclass_(hWnd, @SubclassComboboxList(), uIdSubclass) 

;   Case #WM_LBUTTONDOWN                                                       : Debug "WM_LBUTTONDOWN" 

    Case #WM_RBUTTONDOWN                                                       ;: Debug "WM_RBUTTONDOWN" 
      GetCursorPos_(@pt) 
      ScreenToClient_(hWnd, @pt) 
      index = ((pt\y & $FFFF) << 16) + (pt\x + $FFFF) 
      index = SendMessage_(hWnd, #LB_ITEMFROMPOINT, 0, index) 
      If (index >> 16) & $FFFF  ; inside the listbox or out 
;       index & $FFFF                                   : Debug "  index == " + index + "   outside " 
        ProcedureReturn 0 
      Else 
        index & $FFFF                                   : Debug "WM_RBUTTONDOWN -> index == " + index + "   inside " 

        SetGadgetText(uIdSubclass, GetGadgetItemText(uIdSubclass, index))   ; <= set selected text 
        SendMessage_(GadgetID(uIdSubclass), #CB_SHOWDROPDOWN, #False, 0)    ; <= close the drop down 
        PostEvent(#PB_Event_Gadget, #WND_Main, uIdSubclass, #PB_EventType_RightClick, index) ; <= send a PB_ Style Event, Index as Data not needed.  
      EndIf 
  EndSelect 
  ProcedureReturn DefSubclassProc_(hWnd, uMsg, wParam, lParam) 
EndProcedure


Procedure Main() 
  Protected ii, d, state, hList, cbi.COMBOBOXINFO 

  If OpenWindow(#WND_Main, 0, 0, 456, 200, "Something with Combobox ... ", #PB_Window_ScreenCentered|#PB_Window_SystemMenu) 
    StickyWindow(#WND_Main, 1) ; always on top :) 

    ComboBoxGadget(#GDT_cbbTest, 8, 8, 240, 24) 
      For ii = 0 To 9 
        AddGadgetItem(#GDT_cbbTest, -1, "Test Text Item "+ii) 
      Next 
      SetGadgetState(#GDT_cbbTest, 1) 


    cbi\cbSize = SizeOf(COMBOBOXINFO) 
    If GetComboBoxInfo_(GadgetID(#GDT_cbbTest), @cbi)
      hList = cbi\hwndList                                  : Debug "MAIN: Combobox List hwnd == " + hList 
      SetWindowSubclass_(hList, @SubclassComboboxList(), #GDT_cbbTest, 0)  ; 
    EndIf 

    Repeat
      Select WaitWindowEvent()
        Case #PB_Event_CloseWindow 
          Break ; say good bye. 

        Case #PB_Event_Gadget 
          Select EventGadget() 
            Case #GDT_cbbTest   
              Select EventType() 
                Case #PB_EventType_Change 
                  state = GetGadgetState(#GDT_cbbTest) 
                  Debug "MAIN: EventType_Change " + state 

                Case #PB_EventType_RightClick ; NEW .. NOT supported by PB as default 
                  state = GetGadgetState(#GDT_cbbTest) 
                  d = EventData() ; <= not really needed, because the state is correct already. 
                  Debug "MAIN: EventType_RightClick " + state + ", Data = " + d 

              EndSelect 
          EndSelect 

      EndSelect
    ForEver
  EndIf 
EndProcedure 

End Main() 
Just because it worked doesn't mean it works.
PureBasic 6.04 (x86) and <latest stable version and current alpha/beta> (x64) on Windows 11 Home. Now started with Linux (VM: Ubuntu 22.04).
RobertRioja
User
User
Posts: 86
Joined: Thu May 02, 2019 3:57 am
Location: USA
Contact:

Re: Right-click on a ComboBoxGadget

Post by RobertRioja »

To Axolotl: Your first code does exactly what I need. Your second code is "better" but more than what I need. Thank you.

To all else: Thank you for your efforts. But I now have what I needed.

Rob
Randy Walker
Addict
Addict
Posts: 1077
Joined: Sun Jul 25, 2004 4:21 pm
Location: USoA

Re: Right-click on a ComboBoxGadget

Post by Randy Walker »

Axolotl wrote: Mon Sep 15, 2025 2:32 pm Here is an example of right-click on the dropdown-listbox ..... (Windows Only)
That is a really great code sample there Axolotl. Thanks for sharing!!!
- - - - - - - - - - - - - - - -
Randy
I *never* claimed to be a programmer.
Post Reply