[Class] LV_InCellEdit - update on 2015-12-15

Post your working scripts, libraries and tools
just me
Posts: 5955
Joined: 02 Oct 2013, 08:51
Location: Germany

[Class] LV_InCellEdit - update on 2015-12-15

20 Dec 2013, 04:48

Primarily released at http://www.autohotkey.com/board/topic/7 ... listviews/.

New version v1.2 (requires AHK 1.1.20+).
  • Changed the class to support new instances per control instead of attaching them to the prototype.
  • Added individual message handling per instance which doesn't interfere with other message handlers for WM_NOTIFY messages.
  • Replaced subclassing with message handlers for WM_COMMAND and WM_HOTKEY messages.
  • Changed SetColumns() method to accept variadic parameters.
  • Revised code.
  • Adjusted sample script.
Step 1 -> Step 2 -> Step 3

It took more time than expected to realize step 2:
  • v1.0: Class LV_InCellEdit, but now the basic version seems to work stable. The Listviews refused obstinately to disclose what they are doing during editing and I'm not able to debug scripts. Finally I had to prevent the handling of EN_UPDATE notifications to get things working. This implicates some nasty side-effects and I had to do more off the stuff manually than originally planned. So the difference to the other scripts is a bit less than favored, but it is still a new concept.
It took even more time to realize step 3:
  • v1.1: Navigate thru cells with tab and arrow keys while editing. It was really hard work for me, but now all seems to work reasonably stable.
Change History
Source
View sources on GitHub:
:arrow: https://github.com/AHK-just-me/Class_LV ... er/Sources
Download from GitHub:
:arrow: https://github.com/AHK-just-me/Class_LV ... master.zip
Prior releases on GitHub:
:arrow: https://github.com/AHK-just-me/Class_LV ... t/releases
Last edited by just me on 15 Dec 2015, 02:50, edited 8 times in total.
HotKeyIt
Posts: 1789
Joined: 29 Sep 2013, 18:35
Contact:

Re: [Class] LV_InCellEdit - in-cell editing for ListViews

20 Dec 2013, 09:57

Looks great, thanks for sharing ;)

How about to add LV_InCellEdit() function so it is stdlib compatible.

Code: Select all

LV_InCellEdit(){
   LV_InCellEdit.OnMessage()
}
just me
Posts: 5955
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: [Class] LV_InCellEdit - in-cell editing for ListViews

22 Mar 2014, 04:18

tmplinshi?

Thought I'd seen a question but it vanished in the haze. :roll:
tmplinshi
Posts: 1306
Joined: 01 Oct 2013, 14:57

Re: [Class] LV_InCellEdit - in-cell editing for ListViews

22 Mar 2014, 04:35

Yeah... Because I found that question not very important, and I don't want to trouble you, so I've deleted my question.
But it will be helpful if it can be done. The deleted question is "How to enable editing when a key pressed, Or provide a function to enable editing for specific cell, e.g.: LV_InCellEdit.EnableEdit(HLV, RowNumber, ColNumber)"

Sorry and Thank you :D

Edit: Correct two spell mistakes.
Last edited by tmplinshi on 22 Mar 2014, 19:59, edited 3 times in total.
just me
Posts: 5955
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: [Class] LV_InCellEdit - in-cell editing for ListViews

22 Mar 2014, 04:45

This might give you an idea:

Code: Select all

...
...
...
; ----------------------------------------------------------------------------------------------------------------------
MyListView:
   OutputDebug, %A_GuiControl%: %A_GuiEvent%
   If (A_GuiEvent == "F") {
      GuiControlGet, H, HWND, %A_GuiControl%
      If LV_InCellEdit.Changed.HasKey(H) {
         Msg := ""
         For I, O In LV_InCellEdit.Changed[H] {
            Msg .= "Row " . O.Row . " - Column " . O.Col . " : " . O.Txt
         }
         ToolTip, % "Changes in " . A_GuiControl . "`r`n`r`n" . Msg
         SetTimer, KillToolTip, 2000
         LV_InCellEdit.Changed.Remove(H, "")
      }
   }
   Else If (A_GuiEvent == "K") && (Chr(A_EventInfo) = "e") {   ; <<<<<<<<<< added!
      GuiControlGet, H, HWND, %A_GuiControl%
      If LV_InCellEdit.Attached.HasKey(H) {
         Gui, ListView, %A_GuiControl%
         If (Row := LV_GetNext(0, "Focused"))
            EditLabel(H, Row)
      }
   }

Return
; ----------------------------------------------------------------------------------------------------------------------
KillToolTip:
   ToolTip
Return
; ----------------------------------------------------------------------------------------------------------------------
EditLabel(HLV, Row) {  ; <<<<<<<<<< added!
   ITEM := Row - 1
   If LV_InCellEdit.Attached[HLV].HasKey("Columns")
      SITEM := LV_InCellEdit.Attached[HLV].Columns.MinIndex()
   Else
      SITEM := LV_InCellEdit.Attached[HLV].Skip0 ? 1 : 0
   VarSetCapacity(L, 1024, 0)
   NumPut(ITEM, L, (A_PtrSize * 3) + 0, "Int")
   NumPut(SITEM, L, (A_PtrSize * 3) + 4, "Int")
   LV_InCellEdit.On_NM_DBLCLICK(HLV, &L)
}
It will edit the first possible cell the currently focused row when "e" is pressed.

If you simply want to edit the cell under the mouse cursor, you might just use Click, 2.

;)
tmplinshi
Posts: 1306
Joined: 01 Oct 2013, 14:57

Re: [Class] LV_InCellEdit - in-cell editing for ListViews

22 Mar 2014, 05:39

Thanks. It seems always editing the first colum when "e" pressed. Click, 2 not works very well, sometimes the editing box appears with empty data (failed to getting the original cell data).

Is there a way to specify ColumNumber? I have a function from you, which can get clicked RowNumber and ColumNumber:

Code: Select all

LV_SubItemHitTest(HLV, ByRef Row, ByRef Column) { ; by just me, http://goo.gl/mHPzPk
   Static LVM_SUBITEMHITTEST := 0x1039
   Static LVHT_ONITEM := 0x0000000E
   VarSetCapacity(LVHTI, 24, 0)
   DllCall("User32.dll\GetCursorPos", "Ptr", &LVHTI)
   DllCall("User32.dll\ScreenToClient", "Ptr", HLV, "Ptr", &LVHTI)
   SendMessage, LVM_SUBITEMHITTEST, 0, &LVHTI, , ahk_id %HLV%
   Row := ErrorLevel > 0x7FFFFFFF ? 0 : ErrorLevel + 1
   Column := (NumGet(LVHTI, 8, "UInt") & LVHT_ONITEM) ? NumGet(LVHTI, 16, "Int") + 1 : 0
}
So first store the last clicked RowNumber and ColumNumber, and when a key pressed then enable editing for that cell. Is this can be done?
just me
Posts: 5955
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: [Class] LV_InCellEdit - in-cell editing for ListViews

22 Mar 2014, 05:44

O.K., I will add a method EditCell(HWND, Row, Col := 0) to the class.

So long!
just me
just me
Posts: 5955
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: [Class] LV_InCellEdit - in-cell editing for ListViews

22 Mar 2014, 09:08

Done! ;)

*Update on 2014-03-22*
tmplinshi
Posts: 1306
Joined: 01 Oct 2013, 14:57

Re: [Class] LV_InCellEdit - in-cell editing for ListViews

22 Mar 2014, 10:42

It works great! Thanks a lot!

I'm facing another problem :oops: . I'm trying to use Class_LV_Colors and Class_LV_InCellEdit in one script, but only one of them works. Can they be together?

Code: Select all

LV_Colors.Attach(HLV)
LV_Colors.NoSort(HLV, False)
LV_Colors.OnMessage()

LV_InCellEdit.OnMessage()
LV_InCellEdit.Attach(HLV, True, True)
tmplinshi
Posts: 1306
Joined: 01 Oct 2013, 14:57

Re: [Class] LV_InCellEdit - in-cell editing for ListViews

22 Mar 2014, 19:17

This seems to work: :D

Code: Select all

LV_Colors.Attach(HLV)
LV_Colors.NoSort(HLV, False)
; LV_Colors.OnMessage()

; LV_InCellEdit.OnMessage()
LV_InCellEdit.Attach(HLV, True, True)

OnMessage(0x4E, "WM_NOTIFY")
Return

WM_NOTIFY(W, L) {
	; =================================
	;		LV_InCellEdit_WM_NOTIFY from Class_LV_InCellEdit
	; =================================
	Static LVN_BEGINLABELEDITA := -105
	Static LVN_BEGINLABELEDITW := -175
	Static LVN_ENDLABELEDITA := -106
	Static LVN_ENDLABELEDITW := -176
	Static NM_CLICK := -2
	Static NM_DBLCLICK := -3
	H := NumGet(L + 0, 0, "UPtr")
	M := NumGet(L + (A_PtrSize * 2), 0, "Int")
	If (LV_InCellEdit.Attached.HasKey(H)) {
		; BeginLabelEdit -------------------------------------------------------------------------------------------------
		If (M = LVN_BEGINLABELEDITW) || (M = LVN_BEGINLABELEDITA) {
			Return LV_InCellEdit.On_LVN_BEGINLABELEDIT(H, L)
		}
		; EndLabelEdit ---------------------------------------------------------------------------------------------------
		If (M = LVN_ENDLABELEDITW) || (M = LVN_ENDLABELEDITA) {
			Return LV_InCellEdit.On_LVN_ENDLABELEDIT(H, L)
		}
		; Double click ---------------------------------------------------------------------------------------------------
		If (M = NM_DBLCLICK) {
			LV_InCellEdit.On_NM_DBLCLICK(H, L)
		}
	}
	
	; =================================
	;		LV_Colors_WM_NOTIFY from Class_LV_Colors
	; =================================
	Static NM_CUSTOMDRAW := -12
	Static LVN_COLUMNCLICK := -108
	; Critical
	If LV_Colors.HasKey(H := NumGet(L + 0, 0, "UPtr")) {
		M := NumGet(L + (A_PtrSize * 2), 0, "Int")
		; NM_CUSTOMDRAW --------------------------------------------------------------------------------------------------
		If (M = NM_CUSTOMDRAW)
			Return LV_Colors.On_NM_CUSTOMDRAW(H, L)
		; LVN_COLUMNCLICK ------------------------------------------------------------------------------------------------
		If (LV_Colors[H].NS && (M = LVN_COLUMNCLICK))
			Return 0
	}
}
User avatar
joedf
Posts: 6875
Joined: 29 Sep 2013, 17:08
Facebook: J0EDF
Google: +joedf
GitHub: joedf
Location: Canada, Quebec
Contact:

Re: [Class] LV_InCellEdit - in-cell editing for ListViews

04 Jun 2014, 02:53

Excellent as always! :D
Image Image Image Image Image
Windows 10 x64 Professional, Intel i5-8500 @ 3.00 GHz, 16GB DDR4 3200 MHz, NVIDIA GTX 1060 6GB | [About Me] | [ASPDM - StdLib Distribution]
[Populate the AHK MiniCity!] | [Qonsole - Quake-like console emulator] | [LibCon - Autohotkey Console Library] | [About the AHK Foundation]
Edd
Posts: 42
Joined: 16 Aug 2014, 16:45

Re: [Class] LV_InCellEdit - in-cell editing for ListViews

20 Aug 2014, 02:19

Please someone help me with this, I'm trying to edit every field with normal click instead of double click and also I want to navigate through all the editable fields with "Tab" even if there are not focused, on the code I put the idea, but I can't get this working exactly as I need, I'll aprecciate so much your help, Thanks!

Edit:
I also need to clear the edit field if the user introduce a value that isn't an integer, but I don't know how to do it.

My code:

Code: Select all


#NoEnv
#Include Class_LV_InCellEdit.ahk
SetBatchLines, -1

LV := "
(
Hombre||
Mujer||
Niño||
Niña||
)"
; -----------------------------------------------------------------------------------------------------------------`-----
LVW := 262
Gui, Margin, 20, 20
Gui, Font, s9, Verdana

Gui, Add, ListView, xm y+10 w%LVW% -Readonly -Multi +NoSortHdr Grid r4 gRangosEdad_ListView hwndHRangosEdad AltSubmit vRangosEdad
   , Column 0|Clasificación|Edad Inicial|Edad Limite
Loop, Parse, LV, `n
{
   If (A_LoopField) {
      StringSplit, F, A_LoopField, |
      LV_Add("", "", F1, F2, F3)
      LV_ModifyCol(AutoHdr)
   }
}
LV_ModifyCol(1, 0)


Gui, Show, , Example
LV_InCellEdit.OnMessage()
Gosub, HiddenCol1ListView
Return
; ----------------------------------------------------------------------------------------------------------------------
GuiClose:
GuiEscape:
ExitApp
; ----------------------------------------------------------------------------------------------------------------------
; ----------------------------------------------------------------------------------------------------------------------
HiddenCol1ListView:
   If !(LV_InCellEdit.Attach(HRangosEdad, True, True))
      MsgBox, % "Registering HRangosEdad failed: " . ErrorLevel
    LV_InCellEdit.SetColumns(HRangosEdad, [1, 3, 4])
Return
; ----------------------------------------------------------------------------------------------------------------------
RangosEdad_ListView:
ToolTip
If (A_GuiEvent == "C")
{
LV_ModifyCol(2, 88)
LV_ModifyCol(3, 84)
LV_ModifyCol(4, 85)
}
   OutputDebug, %A_GuiControl%: %A_GuiEvent%
   If (A_GuiEvent == "F") {
      GuiControlGet, H, HWND, %A_GuiControl%
      If LV_InCellEdit.Changed.HasKey(H) {
         Msg := ""
         For I, O In LV_InCellEdit.Changed[H] {
         FR := O.txt
         }
         If FR
         If FR is not Integer
         {
         ;MsgBox, 262192, Atención, Valor no válido
         ValueNotValid = True
         }
         If ValueNotValid =
         LV_InCellEdit.Changed.Remove(H, "")
         else
         {
         ValueNotValid:=
         ToolTip, Empty Cell
         }
      }
   }
Return

F1::
LV_GetText(HR1, 1 , 3)
LV_GetText(HR2, 1 , 4)
ToolTip, % HR1 " - " HR2
return


Tab::
CT++
If LV_InCellEdit.Attached.HasKey(H) {
Gui, ListView, %A_GuiControl%
MsgBox, %CT%
If CT=1
LV_InCellEdit.EditCell(H, 1, 3)
If CT=2
LV_InCellEdit.EditCell(H, 1, 4)
else If CT=3
LV_InCellEdit.EditCell(H, 2, 3)
else If CT=4
LV_InCellEdit.EditCell(H, 2, 4)
else If CT=5
LV_InCellEdit.EditCell(H, 3, 3)
else If CT=6
LV_InCellEdit.EditCell(H, 3, 4)
else If CT=7
LV_InCellEdit.EditCell(H, 4, 3)
else If CT=8
{
LV_InCellEdit.EditCell(H, 4, 4)
CT:=
}
}
return



Edd
Posts: 42
Joined: 16 Aug 2014, 16:45

Re: [Class] LV_InCellEdit - in-cell editing for ListViews

20 Aug 2014, 03:00

I don't use this forum so much, I use more the other ahk forum, so I'm not sure if someone will see my post, I hope it's like the other forum where users can get notifications
User avatar
joedf
Posts: 6875
Joined: 29 Sep 2013, 17:08
Facebook: J0EDF
Google: +joedf
GitHub: joedf
Location: Canada, Quebec
Contact:

Re: [Class] LV_InCellEdit - in-cell editing for ListViews

20 Aug 2014, 03:46

You get email notifications ;)
Image Image Image Image Image
Windows 10 x64 Professional, Intel i5-8500 @ 3.00 GHz, 16GB DDR4 3200 MHz, NVIDIA GTX 1060 6GB | [About Me] | [ASPDM - StdLib Distribution]
[Populate the AHK MiniCity!] | [Qonsole - Quake-like console emulator] | [LibCon - Autohotkey Console Library] | [About the AHK Foundation]
Edd
Posts: 42
Joined: 16 Aug 2014, 16:45

Re: [Class] LV_InCellEdit - in-cell editing for ListViews

20 Aug 2014, 03:50

Ok, thank you joedf! :)

I hope someone can help me soon
just me
Posts: 5955
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: [Class] LV_InCellEdit - in-cell editing for ListViews

20 Aug 2014, 07:58

Something to start with:

Code: Select all

#NoEnv
#Include Class_LV_InCellEdit.ahk
SetBatchLines, -1

LV := "
(
Hombre||
Mujer||
Niño||
Niña||
)"
EditCols := [3, 4]
; -----------------------------------------------------------------------------------------------------------------`-----
LVW := 262
Gui, Margin, 20, 20
Gui, Font, s9, Verdana

Gui, Add, ListView, xm y+10 w%LVW% -Readonly -Multi +NoSortHdr Grid r4 gRangosEdad_ListView hwndHRangosEdad AltSubmit vRangosEdad
   , Column 0|Clasificación|Edad Inicial|Edad Limite
Loop, Parse, LV, `n
{
   If (A_LoopField) {
      StringSplit, F, A_LoopField, |
      LV_Add("", "", F1, F2, F3)
      LV_ModifyCol(AutoHdr)
   }
}
LV_ModifyCol(1, 0)

Gui, Add, Button, , Check!
Gui, Show, , Example
LV_InCellEdit.OnMessage()
Gosub, HiddenCol1ListView
Return
; ----------------------------------------------------------------------------------------------------------------------
GuiClose:
GuiEscape:
ExitApp
; ----------------------------------------------------------------------------------------------------------------------
HiddenCol1ListView:
   If !(LV_InCellEdit.Attach(HRangosEdad, True, True))
      MsgBox, % "Registering HRangosEdad failed: " . ErrorLevel
   LV_InCellEdit.SetColumns(HRangosEdad, EditCols)
Return
; ----------------------------------------------------------------------------------------------------------------------
RangosEdad_ListView:
   Critical ; prevents that some notifications might be lost if the script cannot keep up with them
   If (A_GuiEvent = "Normal") { ; left click
      Col := LV_EX_SubItemHitTest(HRangosEdad)
      For I, EC In EditCols {
         If (Col = EC) {
            LV_InCellEdit.EditCell(HRangosEdad, A_EventInfo, Col)
            Break
         }
      }
   }
   ; ToolTip ; you shouldn't use ToolTips in a ListView g-label.
   If (A_GuiEvent == "C")
   {
      LV_ModifyCol(2, 88)
      LV_ModifyCol(3, 84)
      LV_ModifyCol(4, 85)
   }
   OutputDebug, %A_GuiControl%: %A_GuiEvent%
   If (A_GuiEvent == "F") { ; not sure what you want to achieve here!! <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
      GuiControlGet, H, HWND, %A_GuiControl%
      If LV_InCellEdit.Changed.HasKey(H) {
         Msg := ""
         For I, O In LV_InCellEdit.Changed[H] {
            FR := O.txt
         }
         If FR
            If FR is not Integer
            {
               ;MsgBox, 262192, Atención, Valor no válido
               ValueNotValid = True
            }
            If ValueNotValid =
            LV_InCellEdit.Changed.Remove(H, "")
         else
         {
            ValueNotValid:=
            ; ToolTip, Empty Cell ;
         }
      }
   }
Return

F1::
   LV_GetText(HR1, 1 , 3)
   LV_GetText(HR2, 1 , 4)
   ToolTip, % HR1 " - " HR2
return

; Tab:: Tab and arrow navigation are built-in!!!

; ======================================================================================================================
; LV_EX -> http://ahkscript.org/boards/viewtopic.php?f=6&t=1256
; ======================================================================================================================
; LV_EX_SubItemHitTest - Gets the column (subitem) at the passed coordinates or the position of the mouse cursor.
; ======================================================================================================================
LV_EX_SubItemHitTest(HLV, X := -1, Y := -1) {
   ; LVM_SUBITEMHITTEST = 0x1039 -> http://msdn.microsoft.com/en-us/library/bb761229(v=vs.85).aspx
   VarSetCapacity(LVHTI, 24, 0) ; LVHITTESTINFO
   If (X = -1) || (Y = -1) {
      DllCall("User32.dll\GetCursorPos", "Ptr", &LVHTI)
      DllCall("User32.dll\ScreenToClient", "Ptr", HLV, "Ptr", &LVHTI)
   }
   Else {
      NumPut(X, LVHTI, 0, "Int")
      NumPut(Y, LVHTI, 4, "Int")
   }
   SendMessage, 0x1039, 0, % &LVHTI, , % "ahk_id " . HLV
   Return (ErrorLevel > 0x7FFFFFFF ? 0 : NumGet(LVHTI, 16, "Int") + 1)
}
I'm trying to edit every field with normal click instead of double click ...
Should work!
... and also I want to navigate through all the editable fields with "Tab" even if there are not focused
Is already built-in. But you must not specify the hidden first column as 'editable'.
I also need to clear the edit field if the user introduce a value that isn't an integer, but I don't know how to do it.
Input restrictions are not supported. But you could do a check within LV_InCellEdit.SubClassProc().
Edd
Posts: 42
Joined: 16 Aug 2014, 16:45

Re: [Class] LV_InCellEdit - in-cell editing for ListViews

20 Aug 2014, 13:46

Thank you so much just me!

By the time I added this for my needs on the Library:

Code: Select all


If (N = EN_SETFOCUS)
SendMessage, EM_SETMARGINS, EC_LEFTMARGIN, 0, , % "ahk_id " . L
ControlGetText, EDITTEXT, , % "ahk_id " . L
If EDITTEXT
If EDITTEXT is not Integer
{
This.Cancelled := True
MsgBox, 262192, Atención, Valor no válido
}
SendMessage, LVM_GETSTRINGWIDTH, 0, &EDITTEXT, , % "ahk_id " . H

I just want to say that I love your library, just me ! you did an awesome work! THANKS
Edd
Posts: 42
Joined: 16 Aug 2014, 16:45

Re: [Class] LV_InCellEdit - in-cell editing for ListViews

20 Aug 2014, 14:21

just me, I've a problem about the tab, the thing is that on my main script I have a label to manage the tab actions (Hotkey, Tab, TabLabel)
I need this because on my main script I decide which controls has to be focused, and also I use scintilla so I use TabLabel to jump to the next scintilla control instead of the tab space, but the TabLabel disables the tab function on Class_LV_InCellEdit, so I need some way to fix this.
just me
Posts: 5955
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: [Class] LV_InCellEdit - in-cell editing for ListViews

21 Aug 2014, 01:16

What about context-sensitive hotkeys?

Code: Select all

#If FuncNoneOfMyListViewsHasTheFocus()
...
...
...
#If
FuncNoneOfMyListViewsHasTheFocus() {
   ...
   ...
   ...
}

Return to “Scripts and Functions”

Who is online

Users browsing this forum: No registered users and 47 guests