Howdy,
I needed a way to detect right-clicks in the listview control header (for custom searching, menu popups, etc...) and searching the forum turned up nothing so I combed through the Internet for some help. Found some old VB code and converted it over.
The code is from: http://groups.google.com/group/microsof ... ef5b0575b8
From a guy named Chris Eastwood, apparently. Thanks, whoever you are

Code: Select all
;
#LVM_GETHEADER = 4127
;
Structure HDHITTESTINFO
pt.POINT
flags.l
iItem.l
EndStructure
Enumeration ; Window IDs
#WindowMain
EndEnumeration
Enumeration ; Menu IDs
#MenuPrimary
#MenuPrimaryTest
#MenuSecondary
#MenuSecondaryTest
EndEnumeration
Enumeration ; Gadget IDs
#ListPrimary
#ListSecondary
#ButtonClose
EndEnumeration
Procedure.l WindowCallback(HandleWindow, Message, wParam, lParam)
; Main form callback procedure.
HandleHeader.l
; Store the handle for the listview control's header.
*NotifyHeader.NMHDR
; Notification message header.
TestHit.HDHITTESTINFO
; Store information about header hit testing.
IndexColumn.l
; Store the column index from our header.
Protected iLoop.l
;
Protected lResult.l
;
lResult = #PB_ProcessPureBasicEvents
;
If Message = #WM_NOTIFY
; Received a notify event. Usually passed to the parent container for a control.
*NotifyHeader = lParam
; Receive the message header information passed by the notify event.
If *NotifyHeader\code = #NM_RCLICK
; Right-click event was received.
GetCursorPos_(TestHit\pt)
; Retrieve the cursor position.
ScreenToClient_(*NotifyHeader\hwndFrom, TestHit\pt)
; Translate our coordinates to screen coordinates.
IndexColumn = SendMessage_(*NotifyHeader\hwndFrom, #HDM_HITTEST, 0, TestHit)
; Retrieve the column index from our header control. The call uses the coordinate information we retrieved previously.
If *NotifyHeader\hwndFrom = SendMessage_(GadgetID(#ListPrimary), #LVM_GETHEADER, 0, 0)
; Test if the header clicked is from the 'primary' listview control. #LVM_GETHEADER returns the handle to the header
; control used in the listview control. This is the same handle used as part of the NMHDR (*messageheader) variable.
If IndexColumn = 0
; Right-clicked on the first column.
HoldNumber.s = InputRequester("Number Search", "Please enter a number to search for (eg., '1', '2', '3' or '4')", "")
; For our test, prompt the user for a number used in the primary listview control. We'll search for it.
For iLoop = 0 To CountGadgetItems(#ListPrimary) - 1
; Loop through the number of items in our primary listview control.
If HoldNumber = GetGadgetItemText(#ListPrimary, iLoop, 0)
; Check if the entered number is the same as the one in the listview.
SetGadgetItemState(#ListPrimary, iLoop, #PB_ListIcon_Selected)
; Select the item.
SendMessage_(GadgetID(#ListPrimary), #LVM_ENSUREVISIBLE, iLoop, #False)
; Make sure the newly selected item is visible. Not useful in this example but only if we have many more items.
Break
; We found the item. Break from our loop.
EndIf
;
Next iLoop
;
ElseIf IndexColumn = 1
; User right-clicked on the second column.
DisplayPopupMenu(#MenuPrimary, WindowID(#WindowMain))
; Display a popup menu.
EndIf
;
ElseIf *NotifyHeader\hwndFrom = SendMessage_(GadgetID(#ListSecondary), #LVM_GETHEADER, 0, 0)
;
If IndexColumn = 0
; Right-clicked on the first column.
DisplayPopupMenu(#MenuSecondary, WindowID(#WindowMain))
; Display a popup menu.
ElseIf IndexColumn = 2
; Right-clicked on the first column.
HoldString.s = InputRequester("Text Search", "Please enter text to search in the 3rd column (eg. 'fo').", "")
; For our test, prompt the user for a number used in the primary listview control. We'll search for it.
For iLoop = 0 To CountGadgetItems(#ListSecondary) - 1
; Loop through the number of items in our primary listview control.
If FindString(LCase(GetGadgetItemText(#ListSecondary, iLoop, 2)), LCase(HoldString), 1)
; Check if the 3rd column contains the text we search for.
SetGadgetItemState(#ListSecondary, iLoop, #PB_ListIcon_Selected)
; Select the item.
SendMessage_(GadgetID(#ListSecondary), #LVM_ENSUREVISIBLE, iLoop, #False)
; Make sure the newly selected item is visible. Not useful in this example but only if we have many more items.
Break
; We found the item. Break from our loop.
EndIf
;
Next iLoop
;
EndIf
;
EndIf
;
EndIf
;
EndIf
;
ProcedureReturn lResult
;
EndProcedure
;- Main Program Start
EventID.l
; Variable to hold the window message.
DoQuit.b
; Variable to control whether we quit the window or not. Automatically set to #False.
If OpenWindow(#WindowMain, 0, 0, 400, 120, "Listview Header Test", #PB_Window_MinimizeGadget | #PB_Window_ScreenCentered | #PB_Window_SystemMenu | #PB_Window_TitleBar)
; Create the main window.
;
; AdvancedGadgetEvents(#True)
; Enable advanced gadget events.
ListIconGadget(#ListPrimary, 0, 0, 200, 100, "First", 50, #PB_ListIcon_AlwaysShowSelection | #PB_ListIcon_FullRowSelect | #PB_ListIcon_GridLines)
; Create our primary listview control.
ListIconGadget(#ListSecondary, GadgetX(#ListPrimary) + GadgetWidth(#ListPrimary) + 1, GadgetY(#ListPrimary), 200, 100, "First", 50, #PB_ListIcon_AlwaysShowSelection | #PB_ListIcon_FullRowSelect | #PB_ListIcon_GridLines)
; Create our secondary listview control.
ButtonGadget(#ButtonClose, GadgetX(#ListSecondary) + GadgetWidth(#ListSecondary) - 100, GadgetY(#ListSecondary) + GadgetHeight(#ListSecondary) + 1, 100, 20, "Close")
; Create our close button.
;
SetWindowCallback(@WindowCallback())
; Set the main window callback.
AddGadgetColumn(#ListPrimary, 1, "Second", 50)
AddGadgetColumn(#ListPrimary, 2, "Third", 50)
; Add some dummy columns to our primary listicon.
AddGadgetColumn(#ListSecondary, 1, "Second", 50)
AddGadgetColumn(#ListSecondary, 2, "Third", 50)
; Add some dummy columns to our secondary listicon.
If CreatePopupMenu(#MenuPrimary)
; Create the popup menu used on our primary listview.
MenuItem(#MenuPrimaryTest, "Show Primary Header Info")
; Create a test sub-menu item.
EndIf
;
If CreatePopupMenu(#MenuSecondary)
; Create the popup menu used on our secondary listview.
MenuItem(#MenuSecondaryTest, "Show Secondary Header Info")
; Create a test sub-menu item.
EndIf
;
AddGadgetItem(#ListPrimary, -1, "1" + Chr(10) + "One" + Chr(10) + "This")
AddGadgetItem(#ListPrimary, -1, "2" + Chr(10) + "Two" + Chr(10) + "is")
AddGadgetItem(#ListPrimary, -1, "3" + Chr(10) + "Three" + Chr(10) + "a")
AddGadgetItem(#ListPrimary, -1, "4" + Chr(10) + "Four" + Chr(10) + "test.")
; Add some items to our primary listview control.
AddGadgetItem(#ListSecondary, -1, "1978" + Chr(10) + "The" + Chr(10) + "quick")
AddGadgetItem(#ListSecondary, -1, "2001" + Chr(10) + "brown" + Chr(10) + "fox")
AddGadgetItem(#ListSecondary, -1, "2005" + Chr(10) + "jumped" + Chr(10) + "over")
AddGadgetItem(#ListSecondary, -1, "2050" + Chr(10) + "the" + Chr(10) + "two")
AddGadgetItem(#ListSecondary, -1, "3009" + Chr(10) + "lazy" + Chr(10) + "dogs.")
; Add some items to our secondary listview control.
Repeat
;
EventID = WaitWindowEvent()
;
If EventID = #PB_Event_CloseWindow
; Close the program.
DoQuit = #True
;
ElseIf EventID = #PB_Event_Menu
; Menu Events
If EventMenu() = #MenuPrimaryTest
;
MessageRequester("Primary Test", "The user clicked the second column in the primary listview control.", #PB_MessageRequester_Ok)
;
ElseIf EventMenu() = #MenuSecondaryTest
;
MessageRequester("Secondary Test", "The user clicked the first column in the secondary listview control.", #PB_MessageRequester_Ok)
;
EndIf
;
ElseIf EventID = #PB_Event_Gadget
; Control Events
If EventGadget() = #ButtonClose And EventType() = #PB_EventType_LeftClick : DoQuit = #True : EndIf
; Clicked the close button, close the window.
EndIf
;
Until DoQuit = #True
;
EndIf
Hope it's helpful to someone else. I added comments just in case. Not extremely descriptive but they give a little info.