Jump to content

Double click on an item in a list


Go to solution Solved by robertocm,

Recommended Posts

To catch a double-click on a plain list (not a listview), is a GUIRegisterMsg() +  WM_COMMAND() required, or can it be done more simply within the while loop?

While True
    $nMsg = GUIGetMsg()
    Switch $nMsg
        ;how to catch double-clicks?
        Case $List1
            ConsoleWrite("Clicked on listbox: " &  GUICtrlRead($List1)& @CRLF)
        Case $GUI_EVENT_CLOSE
            Exit
    EndSwitch
WEnd

---

Edit: It misses some double-clicks. Am I doing it wrong?

#include <GDIPlus.au3>
#include <File.au3>
#include <GDIPlus.au3>
#include <Math.au3>
#include <GUIConstantsEx.au3>
#include <ListViewConstants.au3>
#include <GUIListBox.au3>
#include <StaticConstants.au3>
#include <WindowsConstants.au3>

#Region ### START Koda GUI section ### Form=
$Form1 = GUICreate("Form1", 623, 449, 279, 114)
$List1 = GUICtrlCreateList("", 0, 52, 622, 396)
$Label1 = GUICtrlCreateLabel("Label1", 8, 8, 428, 31)

GUIRegisterMsg($WM_COMMAND, "WM_COMMAND")
Global $DoubleClicked = Null

GUISetState(@SW_SHOW)
#EndRegion ### END Koda GUI section ###

Func WM_COMMAND($hWnd, $iMsg, $iwParam, $ilParam)
    #forceref $hWnd, $iMsg
    Local $hWndFrom, $iIDFrom, $iCode, $hWndListBox
    If Not IsHWnd($List1) Then $hWndListBox = GUICtrlGetHandle($List1)
    $hWndFrom = $ilParam
    $iIDFrom = BitAND($iwParam, 0xFFFF)
    $iCode = BitShift($iwParam, 16)

    Switch $hWndFrom
        Case $hWndListBox
            Switch $iCode
                Case $LBN_DBLCLK
                    If Not $DoubleClicked Then $DoubleClicked = 1
            EndSwitch
    EndSwitch
    Return $GUI_RUNDEFMSG
EndFunc

While True
    $nMsg = GUIGetMsg()
    Switch $nMsg
        Case $List1
            ;ConsoleWrite("Clicked on listbox: " &  GUICtrlRead($List1)& @CRLF)
            If $DoubleClicked Then
                $filename = GUICtrlRead($List1)
                ConsoleWrite("Double Clicked! " & $filename & @CRLF)
                ;Fails if filename contains spaces
                RunWait(@comspec & ' /c start ' & $filename, '', @SW_HIDE)
                $DoubleClicked = 0
            EndIf

        Case $GUI_EVENT_CLOSE
            Exit
    EndSwitch
WEnd

 

Edited by littlebigman
Link to comment
Share on other sites

From what I can tell, it misinterprets the very first double-click a single click, and when, later, single-clicking, it reports the first one as a double-click:

Edit: Could it be the GUI loop is called before the WM_COMMAND function, making the "If $DoubleClicked" test unreliable?

Edit: Apparently, it's not a good idead to mix code in the GUI loop and the WM_COMMAND function. taiete's code above works OK.

#include <WindowsConstants.au3>
#include <GUIListBox.au3>
#include <GDIPlus.au3>
#include <GUIConstantsEx.au3>

#Region ### START Koda GUI section ### Form=
$Form1 = GUICreate("Form1", 623, 449, 279, 114)
$List1 = GUICtrlCreateList("", 0, 52, 622, 396)
GUISetState(@SW_SHOW)

GUIRegisterMsg($WM_COMMAND, "WM_COMMAND"); Needed to handle double-click on list widget
Global $DoubleClicked = False ;Used to know if user double-clicked
#EndRegion ### END Koda GUI section ###

Func WM_COMMAND($hWnd, $iMsg, $iwParam, $ilParam)
    #forceref $hWnd, $iMsg
    Local $hWndFrom, $iIDFrom, $iCode, $hWndListBox
    If Not IsHWnd($List1) Then $hWndListBox = GUICtrlGetHandle($List1); BUG? What if $List1 IS a handle?
    $hWndFrom = $ilParam
    $iIDFrom = BitAND($iwParam, 0xFFFF)
    $iCode = BitShift($iwParam, 16)

    Switch $hWndFrom
        Case $hWndListBox
            Switch $iCode
                Case $LBN_DBLCLK
                    If Not $DoubleClicked Then $DoubleClicked = True
            EndSwitch
    EndSwitch
    Return $GUI_RUNDEFMSG ;Makes no difference
EndFunc

GUICtrlSetData($List1, "item1")
GUICtrlSetData($List1, "item2")
While True
    $nMsg = GUIGetMsg()
    Switch $nMsg
        Case $List1
            If $DoubleClicked Then
                ConsoleWrite("Double Clicked ")
                $DoubleClicked = False
            Else
                ConsoleWrite("Single click ")
            EndIf
            ConsoleWrite(GUICtrlRead($List1) & @CRLF)

        Case $GUI_EVENT_CLOSE
            ExitLoop
    EndSwitch
WEnd
Edited by littlebigman
Link to comment
Share on other sites

  • Solution

taietel code adapted for two ListBoxes

#include <GUIConstantsEx.au3>

#include <GUIListBox.au3>
#include <WindowsConstants.au3>

GUICreate("Form1", 400, 350)
$hListBox = GUICtrlCreateList("", 5, 5, 190, 340)
Local $t
For $i=1 To 10
    $t &="Item no."&$i&"|"
Next
GUICtrlSetData(-1,$t)

$mnuLBContext = GUICtrlCreateContextMenu($hListBox)
GUICtrlCreateMenuItem("MenuItem3", $mnuLBContext)
GUICtrlCreateMenuItem("MenuItem2", $mnuLBContext)
GUICtrlCreateMenuItem("MenuItem1", $mnuLBContext)
GUIRegisterMsg($WM_COMMAND, "WM_COMMAND")

$hListBox_2 = GUICtrlCreateList("", 205, 5, 190, 340)
GUICtrlSetData(-1,$t)

GUISetState(@SW_SHOW)

While 1
    Sleep(10)
    Switch GUIGetMsg()
        Case $GUI_EVENT_CLOSE
            Exit
    EndSwitch
WEnd

Func WM_COMMAND($hWnd, $iMsg, $iwParam, $ilParam)
    #forceref $hWnd, $iMsg
    Local $hWndFrom, $iIDFrom, $iCode, $hWndListBox, $hWndListBox_2
    If Not IsHWnd($hListBox) Then $hWndListBox = GUICtrlGetHandle($hListBox)
    If Not IsHWnd($hListBox_2) Then $hWndListBox_2 = GUICtrlGetHandle($hListBox_2)
    $hWndFrom = $ilParam
    $iIDFrom = BitAND($iwParam, 0xFFFF) ; Low Word
    $iCode = BitShift($iwParam, 16) ; Hi Word

    Switch $hWndFrom
        Case $hListBox, $hWndListBox, $hListBox_2, $hWndListBox_2
            Switch $iCode
                Case $LBN_DBLCLK ; Sent when the user double-clicks a string in a list box
                  Switch $iIDFrom
                     Case $hListBox, $hWndListBox
                        ConsoleWrite("ListBox 1 Item " & _GUICtrlListBox_GetCurSel($hListBox) & @CRLF)
                     Case $hListBox_2, $hWndListBox_2
                        ConsoleWrite("ListBox 2 Item " & _GUICtrlListBox_GetCurSel($hListBox_2) & @CRLF)
                  EndSwitch
            EndSwitch
    EndSwitch
    Return $GUI_RUNDEFMSG
EndFunc   ;==>WM_COMMAND

 

Edited by robertocm
Link to comment
Share on other sites

  • 2 weeks later...

Thanks. Too bad catching double-clicks on a list requires handling messages outside the GUi loop.

--

Edit: Out of curiosity, what's the difference between $WM_COMMAND and $WM_NOTIFY, and which function is recommended to handle double-clicks on a list?

GUIRegisterMsg($WM_COMMAND, "WM_COMMAND"); Needed to handle double-click on list widget
GUIRegisterMsg($WM_NOTIFY, "WM_NOTIFY") ;this allows you to capture all window messages.
Global $DoubleClicked = False

Func WM_NOTIFY($hWnd, $iMsg, $wParam, $lParam)
    #forceref $hWnd, $iMsg, $wParam
    ;there are a lot of window messages and they fire all the time.
    ;We'll need to filter the ones we want.
    Local $hWndFrom, $iIDFrom, $iCode, $tNMHDR, $tInfo
    $tNMHDR = DllStructCreate($tagNMHDR, $lParam)
    $iIDFrom = DllStructGetData($tNMHDR, "IDFrom")
    $hWndFrom = HWnd(DllStructGetData($tNMHDR, "hWndFrom")) ;this should give us the handle of the control that triggered the event.
    $iCode = DllStructGetData($tNMHDR, "Code")
    Switch $hWndFrom
        Case $List1 ;Only react to messages from the $List1
            Switch $iCode ;check the type of message
                Case $LBN_DBLCLK ;double click message
                    ConsoleWrite("In WM_NOTIFY, double-click" & @CRLF)
            EndSwitch
    EndSwitch
    ; if you don't return $GUI_RUNDEFMSG, or 0 the rest of the messages won't be handles as they should.
    Return $GUI_RUNDEFMSG
EndFunc

Func WM_COMMAND($hWnd, $iMsg, $iwParam, $ilParam)
    #forceref $hWnd, $iMsg
    Local $hWndFrom, $iIDFrom, $iCode, $hWndListBox
    If Not IsHWnd($List1) Then $hWndListBox = GUICtrlGetHandle($List1); BUG?
    $hWndFrom = $ilParam
    $iIDFrom = BitAND($iwParam, 0xFFFF)
    $iCode = BitShift($iwParam, 16)

    Switch $hWndFrom
        Case $hWndListBox
            Switch $iCode
                Case $LBN_DBLCLK
                    If Not $DoubleClicked Then $DoubleClicked = True
            EndSwitch
    EndSwitch
    Return $GUI_RUNDEFMSG
EndFunc

 

Edited by littlebigman
Link to comment
Share on other sites

WM_NOTIFY is a code sent by a control to its parent window when an event has occurred or the control requires some information, so accordingly wParam will contain identifier of the control sending the message and lParam is a pointer to a NMHDR structure that contains additional information.

WM_COMMAND is a code sent when the user selects a command item from a menu, when a control sends a notification message to its parent window, or when an accelerator keystroke is translate, so accordingly when the message is sent by a control wParam high word will contain the control-defined notification code, wParam low word will contain the control identifier and lPara will contain the handle to the control window.

There is no better, each is used when it's appropriate. If you are interested just to know when a control is click, both can give you the answer but is you are looking for additional information WM_NOTIFY will provide such details.

When the words fail... music speaks.

Link to comment
Share on other sites

Thanks.

For some reason, I can't get the text of the selected item that I double-clicked in the listbox. Could it be because it's read in a WM_COMMAND section?

#include <GUIConstantsEx.au3>
#include <GUIListBox.au3>
#include <WindowsConstants.au3>
#include <array.au3>

#Region
GUICreate("Form1", 200, 350)

$hListBox = GUICtrlCreateList("", 5, 5, 190, 340)
GUICtrlSetData($hListBox,"item1|item2")
#EndRegion

GUIRegisterMsg($WM_COMMAND, "WM_COMMAND")

GUISetState(@SW_SHOW)
;in GUI loop, don't refer to listbox, or double-clicks won't be properly handled
While True
    Sleep(10)
    Switch GUIGetMsg()
        Case $GUI_EVENT_CLOSE
            Exit
    EndSwitch
WEnd

Func WM_COMMAND($hWnd, $iMsg, $iwParam, $ilParam)
    #forceref $hWnd, $iMsg
    Local $hWndFrom, $iIDFrom, $iCode, $hWndListBox
    If Not IsHWnd($hListBox) Then $hWndListBox = GUICtrlGetHandle($hListBox)
    $hWndFrom = $ilParam
    $iIDFrom = BitAND($iwParam, 0xFFFF) ; Low Word
    $iCode = BitShift($iwParam, 16) ; Hi Word

    Switch $hWndFrom
        Case $hListBox, $hWndListBox
            Switch $iCode
                Case $LBN_DBLCLK ; Sent when the user double-clicks a string in a list box
                    ;BAD: Returns an array ConsoleWrite("Item "& _GUICtrlListBox_GetCurSel($hListBox)&@CRLF)
                    ;NO CHANGE Local $selItems = _GUICtrlListBox_GetSelItemsText($hWndListBox)
                    Local $selItems = _GUICtrlListBox_GetSelItemsText($hListBox)
                    ConsoleWrite("Array size: " & UBound($selItems) & @CRLF)
                    ConsoleWrite("Number of items: " & $selItems[0] & @CRLF)
                    ConsoleWrite("Array: " & $selItems & @CRLF)
                    ;BLOCKS _ArrayDisplay($selItems)
                    ;BAD ConsoleWrite("Selected item: " & $selItems[1] & @CRLF) ; Array variable has incorrect number of subscripts or subscript dimension range exceeded.:
            EndSwitch
    EndSwitch
    Return $GUI_RUNDEFMSG
EndFunc   ;==>WM_COMMAND

 

Here's the output:

Quote

Array size: 1
Number of items: 0
Array: 

Link to comment
Share on other sites

Actually it's quite indicate to return from WM_COMMAND as fast as possible and you can do it through a simple Dummy control and do all the processing in your main loop or elsewhere. Here is an example:

#include <Array.au3>

Global $hMain, $cList1, $cList2, $cList3, $cDummy
Global $hList1, $hList2, $hList3, $aMsg

$hMain = GUICreate('Example', 900, 300)
$cList1 = GUICtrlCreateList('', 0, 0, 300, 300)
$cList2 = GUICtrlCreateList('', 300, 0, 300, 300)
$cList3 = GUICtrlCreateList('', 600, 0, 300, 300)
$cDummy = GUICtrlCreateDummy()
$hList1 = GUICtrlGetHandle($cList1)
$hList2 = GUICtrlGetHandle($cList2)
$hList3 = GUICtrlGetHandle($cList3)
GUISetState(@SW_SHOW, $hMain)

GUIRegisterMsg(0x0111, 'WM_COMMAND') ; WM_COMMAND

; Add some lines in each list
For $Index = 1 To 5
    GUICtrlSetData($cList1, 'Line ' & $Index)
    GUICtrlSetData($cList2, 'Line ' & $Index)
    GUICtrlSetData($cList3, 'Line ' & $Index)
Next

While True
    Switch GUIGetMsg()
        Case -3 ; GUI_EVENT_CLOSE
            Exit
        Case $cDummy
            $aMsg = StringSplit(GUICtrlRead($cDummy), '|')
            Switch $aMsg[1]
                Case $cList1
                    Switch $aMsg[2]
                        Case 1 ; LBN_SELCHANGE
                            ConsoleWrite('Selection changed in first list.' & @CRLF)
                        Case 2 ; LBN_DBLCLK
                            ConsoleWrite('Double clicked in first list. (Item text: ' & GUICtrlRead($cList1) & ')' & @CRLF)
                    EndSwitch
                Case $cList2
                    Switch $aMsg[2]
                        Case 1 ; LBN_SELCHANGE
                            ConsoleWrite('Selection changed in second list.' & @CRLF)
                        Case 2 ; LBN_DBLCLK
                            ConsoleWrite('Double clicked in second list. (Item text: ' & GUICtrlRead($cList2) & ')' & @CRLF)
                    EndSwitch
                Case $cList3
                    Switch $aMsg[2]
                        Case 1 ; LBN_SELCHANGE
                            ConsoleWrite('Selection changed in third list.' & @CRLF)
                        Case 2 ; LBN_DBLCLK
                            ConsoleWrite('Double clicked in third list. (Item text: ' & GUICtrlRead($cList3) & ')' & @CRLF)
                    EndSwitch
            EndSwitch
    EndSwitch
    Sleep(10)
WEnd

Func WM_COMMAND($hWnd, $iMsg, $wParam, $lParam)
    #forceref $hWnd, $iMsg
    Local $iCtrlID = BitAND($wParam, 0xFFFF) ; Low Word
    Local $iNotificationCode = BitShift($wParam, 16) ; Hi Word
    Switch $lParam  ; Control handle
        Case $hList1, $hList2, $hList3
            GUICtrlSendToDummy($cDummy, $iCtrlID &  '|' & $iNotificationCode)
    EndSwitch
    Return 'GUI_RUNDEFMSG' ; GUI_RUNDEFMSG
EndFunc

 

Edited by Andreik

When the words fail... music speaks.

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...