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: 609
Joined: 04 Oct 2017, 20:04

How to tell a single click from a rapid double click

Post by songdg » 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
mikeyww
Posts: 27192
Joined: 09 Sep 2014, 18:38

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

Post by mikeyww » 07 May 2024, 04:19

Hello,

Have you tried the :arrow: example?

User avatar
flyingDman
Posts: 2832
Joined: 29 Sep 2013, 19:01

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

Post by flyingDman » 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: 609
Joined: 04 Oct 2017, 20:04

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

Post by songdg » 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: 2832
Joined: 29 Sep 2013, 19:01

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

Post by flyingDman » 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: 609
Joined: 04 Oct 2017, 20:04

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

Post by songdg » 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.

User avatar
andymbody
Posts: 939
Joined: 02 Jul 2017, 23:47

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

Post by andymbody » Today, 05:52

flyingDman wrote:
07 May 2024, 18:52
As a side note...

flyingDman... I tried to get Enter key to also work in your example. Do you know why NM_RETURN (-4) does not trigger an event to call the designated method? NM_KEYDOWN (-15) doesn't work either. I think it might have something to do with the external double-click event, which is not triggered by keyboard events. Does that sound accurate? Is there a way to get Listview to respond to keyboard events directly without creating external hotkeys?

The EnterKey method is within the class you provided. I just did not include the rest of your code here

Code: Select all

This.EnterKeyFunc := ObjBindMethod(This, "EnterKey")
LV.OnNotify(NM_RETURN:=-4, This.EnterKeyFunc)	; EnterKey method is never called/triggered

EnterKey(LV, L)
{
	MsgBox "[" L "]"
}


Post Reply

Return to “Ask for Help (v2)”