How to tell a single click from a rapid double click Topic is solved

Get help with using AutoHotkey (v2 or newer) and its commands and hotkeys
songdg
Posts: 605
Joined: 04 Oct 2017, 20:04

How to tell a single click from a rapid double click

06 May 2024, 21:55

How to tell a single click from a rapid double click, I want to checked/unchecked a row of a ListView with checkbox by clicking on the text of that row so I use the ToggleCheck function, also I use LVICE_XXS viewtopic.php?f=83&t=94046 when double click triggers in-cell editing. The problem is when double click a cell it also tick or untick a row at the same time.

Code: Select all

S := []
ToggleCheck(GuiCtrlObj, Item) {
    If S[Item] {
        LV.Modify(Item, '-Check')
        S[Item] := False
    } Else {
        LV.Modify(Item, 'Check')
        S[Item] := True
    }
}
User avatar
flyingDman
Posts: 2828
Joined: 29 Sep 2013, 19:01

Re: How to tell a single click from a rapid double click  Topic is solved

07 May 2024, 18:52

Short answer: you can't.
I would do something like this. Check / uncheck using doubleclick and edit using right click.

Code: Select all

g := Gui("+AlwaysOnTop")
LV := g.AddListView("w200 r12 -readonly checked", ["name","items"])
loop 12
	LV.Add(, "Name " A_Index,"Item " A_Index * 10)
LV.modifycol(1, 90)
LV.modifycol(2, 90)
LV.OnEvent("doubleclick", LVClick)
g.Show()
g.OnEvent("Close", (*) => ExitApp())
LVICE := LVICE_XXS(LV)

LVClick(LV, Item,*)
	{
		{
		ItemState := SendMessage(0x102C, item - 1, 0xF000, LV)
		if !((ItemState >> 12) - 1)
			LV.Modify(item,	"Check")
		else
			LV.Modify(item,	"-Check")
		}
	}

; ======================================================================================================================
;  Class LVICE_XXS      - ListView in-cell editing for AHK v2 - minimal version (changed to edit with rightclick)
; ======================================================================================================================

Class LVICE_XXS {
   ; -------------------------------------------------------------------------------------------------------------------
   __New(LV) {
      If (Type(LV) != "Gui.ListView")
         Throw Error("Class LVICE requires a GuiControl object of type Gui.ListView!")
      This.RightClickFunc := ObjBindMethod(This, "RightClick")
      This.BeginLabelEditFunc := ObjBindMethod(This, "BeginLabelEdit")
      This.EndLabelEditFunc := ObjBindMethod(This, "EndLabelEdit")
      This.CommandFunc := ObjBindMethod(This, "Command")
      LV.OnNotify(-5, This.RightClickFunc)
      This.LV := LV
      This.HWND := LV.Hwnd
      This.Changes := []
   }
   ; -------------------------------------------------------------------------------------------------------------------
   __Delete() {
      If DllCall("IsWindow", "Ptr", This.HWND, "UInt")
         This.LV.OnNotify(-3, This.RightClickFunc, 0)
      This.RightClickFunc := ""
      This.BeginLabelEditFunc := ""
      This.EndLabelEditFunc := ""
      This.CommandFunc := ""
   }
   ; -------------------------------------------------------------------------------------------------------------------
   ; NM_DBLCLK (list view) notification
   ; -------------------------------------------------------------------------------------------------------------------
   RightClick(LV, L) {
      Critical -1
      Item := NumGet(L + (A_PtrSize * 3), 0, "Int")
      Subitem := NumGet(L + (A_PtrSize * 3), 4, "Int")
      CellText := LV.GetText(Item + 1, SubItem + 1)
      RC := Buffer(16, 0)
      NumPut("Int", 0, "Int", SubItem, RC)
      DllCall("SendMessage", "Ptr", LV.Hwnd, "UInt", 0x1038, "Ptr", Item, "Ptr", RC) ; LVM_GETSUBITEMRECT
      This.CX := NumGet(RC, 0, "Int")
      If (Subitem = 0)
         This.CW := DllCall("SendMessage", "Ptr", LV.Hwnd, "UInt", 0x101D, "Ptr", 0, "Ptr", 0, "Int") ; LVM_GETCOLUMNWIDTH
      Else
         This.CW := NumGet(RC, 8, "Int") - This.CX
      This.CY := NumGet(RC, 4, "Int")
      This.CH := NumGet(RC, 12, "Int") - This.CY
      This.Item := Item
      This.Subitem := Subitem
      This.LV.OnNotify(-175, This.BeginLabelEditFunc)
      DllCall("PostMessage", "Ptr", LV.Hwnd, "UInt", 0x1076, "Ptr", Item, "Ptr", 0) ; LVM_EDITLABEL
   }
   ; -------------------------------------------------------------------------------------------------------------------
   ; LVN_BEGINLABELEDIT notification
   ; -------------------------------------------------------------------------------------------------------------------
   BeginLabelEdit(LV, L) {
      Critical -1
      This.HEDT := DllCall("SendMessage", "Ptr", LV.Hwnd, "UInt", 0x1018, "Ptr", 0, "Ptr", 0, "UPtr")
      This.ItemText := LV.GetText(This.Item + 1, This.Subitem + 1)
      DllCall("SendMessage", "Ptr", This.HEDT, "UInt", 0x00D3, "Ptr", 0x01, "Ptr", 4) ; EM_SETMARGINS, EC_LEFTMARGIN
      DllCall("SendMessage", "Ptr", This.HEDT, "UInt", 0x000C, "Ptr", 0, "Ptr", StrPtr(This.ItemText)) ; WM_SETTEXT
      DllCall("SetWindowPos", "Ptr", This.HEDT, "Ptr", 0, "Int", This.CX, "Int", This.CY,
                              "Int", This.CW, "Int", This.CH, "UInt", 0x04)
      OnMessage(0x0111, This.CommandFunc, -1)
      This.LV.OnNotify(-175, This.BeginLabelEditFunc, 0)
      This.LV.OnNotify(-176, This.EndLabelEditFunc)
      Return False

   }
   ; -------------------------------------------------------------------------------------------------------------------
   ; LVN_ENDLABELEDIT notification
   ; -------------------------------------------------------------------------------------------------------------------
   EndLabelEdit(LV, L) {
      Static OffText := 16 + (A_PtrSize * 4)
      Critical -1
      This.LV.OnNotify(-176, This.EndLabelEditFunc, 0)
      OnMessage(0x0111, This.CommandFunc, 0)
      If (TxtPtr := NumGet(L, OffText, "UPtr")) {
         ItemText := StrGet(TxtPtr)
         If (ItemText != This.ItemText) {
            LV.Modify(This.Item + 1, "Col" . (This.Subitem + 1), ItemText)
            This.Changes.Push({Row: This.Item + 1, Col: This.Subitem + 1})
         }
      }
      Return False
   }
   ; -------------------------------------------------------------------------------------------------------------------
   ; WM_COMMAND notification
   ; -------------------------------------------------------------------------------------------------------------------
   Command(W, L, M, H) {
      Critical -1
      If (L = This.HEDT) {
         N := (W >> 16) & 0xFFFF
         If (N = 0x0400) || (N = 0x0300) || (N = 0x0100) { ; EN_UPDATE | EN_CHANGE | EN_SETFOCUS
            DllCall("SetWindowPos", "Ptr", L, "Ptr", 0, "Int", This.CX, "Int", This.CY,
                                    "Int", This.CW, "Int", This.CH, "UInt", 0x04)
         }
      }
   }
}	
14.3 & 1.3.7
songdg
Posts: 605
Joined: 04 Oct 2017, 20:04

Re: How to tell a single click from a rapid double click

08 May 2024, 03:39

@flyingDman
Thanks for providing a neat solution :thumbup: . There's another problem, can I make the Class LVICE_XXS behave differently, if the ListView have checkboxes at the left side then use doubleclick for check / uncheck and right click for edit, otherwise use doubleclick for edit(cancel the right click for edit function).
User avatar
flyingDman
Posts: 2828
Joined: 29 Sep 2013, 19:01

Re: How to tell a single click from a rapid double click

08 May 2024, 14:00

I do not understand the question or the problem. You will determine in you script whether the Listiview has checkboxes or not. If it does have checkboxes you can use the modified Class so that a rightclick edits the cell and a doubleclick checks the box. If it does not have checkboxes you can use the original Class so that a doubleclick edits the cell. So depending on whether the listview has checkboxes or not, use one or the other version of the Class.
14.3 & 1.3.7
songdg
Posts: 605
Joined: 04 Oct 2017, 20:04

Re: How to tell a single click from a rapid double click

09 May 2024, 21:58

flyingDman wrote:
08 May 2024, 14:00
I do not understand the question or the problem. You will determine in you script whether the Listiview has checkboxes or not. If it does have checkboxes you can use the modified Class so that a rightclick edits the cell and a doubleclick checks the box. If it does not have checkboxes you can use the original Class so that a doubleclick edits the cell. So depending on whether the listview has checkboxes or not, use one or the other version of the Class.
I was thinking is it possible to merge them into one by providing a parameter about whether the listview has checkboxes to the LVICE_XXS Class, but use two versions of the Class is a simple and easy way, anyway thank you very much.

Return to “Ask for Help (v2)”

Who is online

Users browsing this forum: emp00, robinson and 26 guests