/*
**********************************
以下为LISTVIEW编辑类控件
**********************************
*/
; ==================================================================================================================================
; Namespace: LV_InCellEdit
; Function: Support for in-cell ListView editing.
; Tested with: AHK 1.1.24.00 (1.1.20+ required)
; Tested on: Win 10 Pro (x64)
; Change History: 1.3.00.00/2016-07-21/just me - Code revision + new options.
; 1.2.02.00/2015-12-14/just me - Bug fix and support for centered columns.
; 1.2.01.00/2015-09-08/just me - Added EditUserFunc option.
; 1.2.00.00/2015-03-29/just me - New version based on AHK 1.1.20+ features.
; 1.1.04.00/2014-03-22/just me - Added method EditCell
; 1.1.03.00/2012-05-05/just me - Added back option BlankSubItem for method Attach
; 1.1.02.00/2012-05-01/just me - Added method SetColumns
; 1.1.01.00/2012-03-18/just me
; ==================================================================================================================================
; CLASS LV_InCellEdit
;
; Unlike other in-cell editing scripts, this class is using the ListViews built-in edit control.
; Advantage:
; You don't have to care about the font and the GUI, and most of the job can be done by handling common ListView
; notifications.
; Disadvantage:
; I've still found no way to prevent the ListView from blanking out the first subitem of the row while editing another
; subitem. The only known workaround is to add a hidden first column.
;
; The class provides methods to restrict editing to certain columns, to directly start editing of a specified cell, and to
; deactivate/activate the built-in message handler for WM_NOTIFY messages (see below).
;
; The message handler for WM_NOTIFY messages will be activated for the specified ListView whenever a new instance is created.
; As long as the message handler is activated a double-click on any cell will show an Edit control within this cell allowing to
; edit the current content. The default behavior for editing the first column by two subsequent single clicks is disabled.
; You have to press "Esc" to cancel editing, otherwise the content of the Edit will be stored in the current cell.
; ListViews must have the -ReadOnly option to be editable.
;
; While editing, "Esc", "Tab", "Shift+Tab", "Down", and "Up" keys are registered as hotkeys. "Esc" will cancel editing without
; changing the value of the current cell. All other hotkeys will store the content of the edit in the current cell and continue
; editing for the next (Tab), previous (Shift+Tab), upper (Up), or lower (Down) cell. You cannot use the keys for other purposes
; while editing.
;
; All changes are stored in MyInstance.Changed. You may track the changes by triggering (A_GuiEvent == "F") in the ListView's
; g-Label and checking MyInstance["Changed"] as shown in the sample scipt. If "True", MyInstance.Changed contains an array of
; objects with keys "Row" (row number), "Col" (column number), and "Txt" (new content).
; Changed may be deleted by the script whenever it is needed.
;
; If you want to temporarily disable in-cell editing call MyInstance.OnMessage(False). To enable it again, call
; MyInstance.OnMessage().
;
; To avoid the loss of Gui events and messages the message handler might need to be 'critical'. This can be achieved by setting
; the instance property 'Critical' to the required value (e.g. MyInstance.Critical := 100).
; New instances default to 'Critical, Off'. Though sometimes needed, ListViews or the whole Gui may become unresponsive under
; certain circumstances if Critical is set and the ListView has a g-label.
;类LV_InCellEdit
;与其他单元内编辑脚本不同,这个类使用的是ListViews内置的编辑控件。
;优势:
;你不需要关心字体和GUI,大部分工作可以通过处理common ListView来完成
;通知。
;劣势:
;我仍然发现没有办法防止ListView从空白的第一个子项的行,而编辑另一个
;子项。
;已知的唯一解决方案是添加一个隐藏的第一列。
;类提供了一些方法,以限制对某些列的编辑,直接开始编辑指定的单元格,以及
;取消激活/激活WM_NOTIFY消息的内置消息处理程序(见下文)。
;;WM_NOTIFY消息的消息处理程序将在创建新实例时为指定的ListView激活。
;只要消息处理程序被激活,双击任何单元格都会显示该单元格内的编辑控件
;编辑当前内容。禁用后续两次单击编辑第一列的默认行为。
;您必须按“Esc”来取消编辑,否则编辑的内容将存储在当前单元格中。
;ListViews必须具有-ReadOnly选项才能编辑。
;;编辑时,“Esc”、“Tab”、“Shift+Tab”、“Down”和“Up”键注册为热键。“Esc”将取消编辑
;更改当前单元格的值。所有其他热键将在当前单元格中存储编辑的内容并继续
;编辑下一个(标签),上一个(Shift+标签),上(上),或下(下)单元格。您不能将密钥用于其他目的;当编辑。
;;所有更改都存储在MyInstance.Changed中。你可以通过在ListView中触发(A_GuiEvent == "F")来跟踪变化
;g-Label并检查MyInstance["Changed"],如示例脚本所示。如果“True”,MyInstance。changes包含一个数组
;对象的键“Row”(行号)、“Col”(列号)和“Txt”(新内容)。;更改后的可以在需要时被脚本删除。
;;如果您想临时禁用单元内编辑,请调用MyInstance.OnMessage(False)。要再次启用它,请调用
;MyInstance.OnMessage()。
;;为了避免Gui事件和消息的丢失,消息处理程序可能需要是“关键的”。这可以通过设置来实现
;实例属性“Critical”到所需的值(例如MyInstance。关键:= 100)。
;新实例默认为'Critical, Off'。虽然有时需要,ListViews或整个Gui可能会变得无响应;在某些情况下,如果设置了Critical并且ListView有g-label。
; ==================================================================================================================================
Class LV_InCellEdit {
; ===============================================================================================================================
; Constructor Creates a new LV_InCellEdit instance for the specified ListView.
; Parameters: HWND - The ListView's HWND.
; Optional ------------------------------------------------------------------------------------------------------
; BlankSubItem - Blank out subitems text while editing.
; Values: True / False
; Default: False
; ScrollToLeft - Per default, edited columns are scrolled only until they are fully visible.
; Set this parameter to True to scroll the columns to the left edge of the ListView.
; Values: True / False
; Default: False (use default scrolling).
; UseColumnWidth - Per default, the width of the edit control is determined by the width of its text.
; Set this parameter to true to let the edit fill the whole column.
; Values: True / False
; Default: False (use default scrolling).
; EditUserFunc - The name of a user-defined funtion to be called from
; LVN_BEGINEDITLABEL and LVN_ENDEDITLABEL.
; The function must accept at least 6 Parameters:
; State - The state of the edit operation: BEGIN / END
; HLV - The handle to the ListView.
; HED - The handle to the edit control.
; Row - The row number of the edited item.
; Col - The column number of the edited item.
; Text - The edited item's text before / after editing.
; To avoid the loss of messages the function should return as soon as possible.
; Note: The BlankSubItem, ScrollToLeft, and UseColumnWidth properties may be changed dynamically after the instance
; has been created.
; ===============================================================================================================================
__New(HWND, BlankSubItem := False, ScrollToLeft := False, UseColumnWidth := False, EditUserFunc := "") {
If (This.Base.Base.__Class) ; do not instantiate instances
Return False
If LV_InCellEdit.Attached[HWND] ; HWND is already attached
Return False
If !DllCall("IsWindow", "Ptr", HWND) ; invalid HWND
Return False
VarSetCapacity(Class, 512, 0)
DllCall("GetClassName", "Ptr", HWND, "Str", Class, "Int", 256)
If (Class <> "SysListView32") ; HWND doesn't belong to a ListView
Return False
If (EditUserFunc <> "") && (Func(EditUserFunc).MaxParams < 6)
Return False
; ----------------------------------------------------------------------------------------------------------------------------
ControlGet, Styles, Style, , , ahk_id %HWND%
If !(Styles & 0x0200) ; LVS_EDITLABELS
GuiControl, +0x0200, %HWND%
This.Styles := Styles
; Set LVS_EX_DOUBLEBUFFER (0x010000) style to avoid drawing issues.
DllCall("SendMessage", "Ptr", HWND, "UInt", 0x1036, "Ptr", 0x010000, "Ptr", 0x010000) ; LVM_SETEXTENDEDLISTVIEWSTYLE
This.HWND := HWND
This.HEDT := 0
This.HHDR := DllCall("SendMessage", "Ptr", HWND, "UInt", 0x101F, "Ptr", 0, "Ptr", 0, "UPtr") ; LVM_GETHEADER
This.Item := -1
This.Subitem := -1
This.ItemText := ""
This.MaxItem := 0
This.MaxSubitem := 0
This.Cancelled := False
This.Next := False
This.BlankSubitem := !!BlankSubItem
This.ScrollToLeft := !!ScrollToLeft
This.UseColumnWidth := !!UseColumnWidth
This.Critical := "Off"
This.Col1W := 0
This.MinW := 0
This.ExtW := 0
If (EditUserFunc <> "")
This.EditUserFunc := Func(EditUserFunc)
This.OnMessage()
LV_InCellEdit.Attached[HWND] := True
}
; ===============================================================================================================================
; Destructor
; ===============================================================================================================================
__Delete() {
LV_InCellEdit.Attached.Delete(This.HWND)
If !(This.Styles & 0x0200)
GuiControl, -0x0200, % This.HWND
This.OnMessage(False)
}
; ===============================================================================================================================
; EditCell Edit the specified cell, if possible.
; Parameters: Row - 1-based row number
; Col - 1-based column number
; Default: 0 - edit the first editable column
; Return values: True on success; otherwise False
; ===============================================================================================================================
EditCell(Row, Col := 0) {
If !(H := This.HWND)
Return False
Rows := DllCall("SendMessage", "Ptr", H, "UInt", 0x1004, "Ptr", 0, "Ptr", 0, "Int") ; LVM_GETITEMCOUNT
If (Row < 1) || (Row > Rows)
Return False
This.MaxItem := Rows - 1
Cols := DllCall("SendMessage", "Ptr", This.HHDR, "UInt", 0x1200, "Ptr", 0, "Ptr", 0, "Int") ; HDM_GETITEMCOUNT
This.MaxSubitem := Cols - 1
If (Col = 0)
If This["Columns"]
Col := This.Columns.MinIndex() + 1
Else
Loop, %Cols%
Col := A_Index
Until (DllCall("SendMessage", "Ptr", H, "UInt", 0x101D, "Ptr", Col - 1, "Ptr", 0, "Int") > 0) ; LVM_GETCOLUMNWIDTH
If (Col < 1) || (Col > Cols)
Return False
If (This["Columns"]) && (!This.Columns[Col - 1])
Return False
If !(DllCall("SendMessage", "Ptr", H, "UInt", 0x101D, "Ptr", Col - 1, "Ptr", 0, "Int") > 0)
Return False
This.DoubleClick(--Row, --Col)
Return True
}
; ===============================================================================================================================
; SetColumns Sets the columns you want to edit
; Parameters: ColNumbers* - zero or more numbers of columns which shall be editable. If entirely omitted,
; the ListView will be reset to enable editing of all columns.
; Return values: True on success; otherwise False
; Note: All passed editable columns must be visible!
; ===============================================================================================================================
SetColumns(ColNumbers*) {
If !(H := This.HWND)
Return False
This.Delete("Columns")
If (ColNumbers.MinIndex() = "")
Return True
ColCount := DllCall("SendMessage", "Ptr", This.HHDR, "UInt", 0x1200, "Ptr", 0, "Ptr", 0, "Int") ; HDM_GETITEMCOUNT
Cols := []
For Each, Col In ColNumbers {
If Col Is Not Integer
Return False
If (Col < 1) || (Col > ColCount)
Return False
If !(DllCall("SendMessage", "Ptr", H, "UInt", 0x101D, "Ptr", Col - 1, "Ptr", 0, "Int") > 0) ; LVM_GETCOLUMNWIDTH
Return False
Cols[Col - 1] := True
}
This["Columns"] := Cols
Return True
}
; ===============================================================================================================================
; OnMessage Activate / deactivate the message handler for WM_NOTIFY messages for this ListView
; Parameters: Apply - True / False
; Default: True
; Return Value: Always True
; ===============================================================================================================================
OnMessage(Apply := True) {
If !This.HWND
Return False
If (Apply) && !This["NotifyFunc"] {
This.NotifyFunc := ObjBindMethod(This, "On_WM_NOTIFY")
OnMessage(0x004E, This.NotifyFunc, -1) ; add the WM_NOTIFY message handler
}
Else If !(Apply) && This["NotifyFunc"] {
OnMessage(0x004E, This.NotifyFunc, 0) ; remove the WM_NOTIFY message handler
This.NotifyFunc := ""
}
WinSet, Redraw, , % "ahk_id " . This.HWND
Return True
}
; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; PRIVATE PROPERTIES AND METHODS ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Static Attached := {}
Static OSVersion := DllCall("GetVersion", "UChar")
; -------------------------------------------------------------------------------------------------------------------------------
; WM_COMMAND message handler for edit notifications
; -------------------------------------------------------------------------------------------------------------------------------
On_WM_COMMAND(W, L, M, H) {
; LVM_GETSTRINGWIDTHW = 0x1057, LVM_GETSTRINGWIDTHA = 0x1011
Critical, % This.Critical
If (L = This.HEDT) {
N := (W >> 16)
If (N = 0x0400) || (N = 0x0300) || (N = 0x0100) { ; EN_UPDATE | EN_CHANGE | EN_SETFOCUS
If (N = 0x0400) && !This.UseColumnWidth {
ControlGetText, EditText, , % "ahk_id " . L
EW := DllCall("SendMessage", "Ptr", This.HWND, "UInt", A_IsUnicode ? 0x1057 : 0x1011, "Ptr", 0, "Ptr", &EditText, "Int") ; LVM_GETSTRINGWIDTH
, EW += This.ExtW
If (EW < This.MinW)
EW := This.MinW
If (This.EX + EW) > This.ClientW
EW := This.ClientW - This.EX
This.EW := EW
}
DllCall("SetWindowPos", "Ptr", L, "Ptr", 0, "Int", This.EX, "Int", This.EY, "Int", This.EW, "Int", This.EH, "UInt", 0x04)
}
}
}
; -------------------------------------------------------------------------------------------------------------------------------
; WM_HOTKEY message handler
; -------------------------------------------------------------------------------------------------------------------------------
On_WM_HOTKEY(W, L, M, H) {
; LVM_CANCELEDITLABEL = 0x10B3, Hotkeys: 0x801B (Esc -> cancel)
Critical, % This.Critical
If (H = This.HWND) {
If (W = 0x801B) { ; Esc
This.Cancelled := True
, DllCall("PostMessage", "Ptr", H, "UInt", 0x10B3, "Ptr", 0, "Ptr", 0)
}
Else {
This.Next := True
, DllCall("SendMessage", "Ptr", H, "UInt", 0x10B3, "Ptr", 0, "Ptr", 0)
, This.Next := True
, This.NextSubitem(W)
}
Return False
}
}
; -------------------------------------------------------------------------------------------------------------------------------
; WM_NOTIFY message handler for ListView notifications
; -------------------------------------------------------------------------------------------------------------------------------
On_WM_NOTIFY(W, L) {
Critical, % This.Critical
If (H := NumGet(L + 0, 0, "UPtr") = This.HWND) {
M := NumGet(L + (A_PtrSize * 2), 0, "Int")
; BeginLabelEdit -------------------------------------------------------
If (M = -175) || (M = -105) ; LVN_BEGINLABELEDITW || LVN_BEGINLABELEDITA
Return This.LVN_BEGINLABELEDIT(L)
; EndLabelEdit ---------------------------------------------------------
If (M = -176) || (M = -106) ; LVN_ENDLABELEDITW || LVN_ENDLABELEDITA
Return This.LVN_ENDLABELEDIT(L)
; Double click ---------------------------------------------------------
If (M = -3) ; NM_DBLCLICK
This.NM_DBLCLICK(L)
}
}
; -------------------------------------------------------------------------------------------------------------------------------
; LVN_BEGINLABELEDIT notification
; -------------------------------------------------------------------------------------------------------------------------------
LVN_BEGINLABELEDIT(L) {
If (This.Item = -1) || (This.Subitem = -1)
Return True
SetControlDelay, -1
H := This.HWND, Item := This.Item, SubItem := This.Subitem
This.HEDT := HEDT := DllCall("SendMessage", "Ptr", H, "UInt", 0x1018, "Ptr", 0, "Ptr", 0, "UPtr")
, DllCall("SendMessage", "Ptr", HEDT, "UInt", 0x00D3, "Ptr", 0x01, "Ptr", 0) ; EM_SETMARGINS, EC_LEFTMARGIN
, VarSetCapacity(ItemText, 2048, 0) ; text buffer
, VarSetCapacity(LVITEM, 40 + (A_PtrSize * 5), 0) ; LVITEM structure
, NumPut(Item, LVITEM, 4, "Int"), NumPut(Subitem, LVITEM, 8, "Int")
, NumPut(&ItemText, LVITEM, 16 + A_PtrSize, "Ptr") , NumPut(1024 + 1, LVITEM, 16 + (A_PtrSize * 2), "Int") ; pszText, cchTextMax
, DllCall("SendMessage", "Ptr", H, "UInt", A_IsUnicode ? 0x1073 : 0x102D, "Ptr", Item, "Ptr", &LVITEM) ; LVM_GETITEMTEXT
, This.ItemText := StrGet(&ItemText)
; Call the user function, if any
If (This.EditUserFunc)
This.EditUserFunc.Call("BEGIN", H, HEDT, Item + 1, Subitem + 1, This.ItemText)
DllCall("SendMessage", "Ptr", This.HEDT, "UInt", 0x000C, "Ptr", 0, "Ptr", &ItemText) ; WM_SETTEXT
If (Subitem > 0) && (This.BlankSubitem) {
Empty := ""
, NumPut(&Empty, LVITEM, 16 + A_PtrSize, "Ptr") ; pszText in LVITEM
, NumPut(0, LVITEM, 16 + (A_PtrSize * 2), "Int") ; cchTextMax in LVITEM
, DllCall("SendMessage", "Ptr", H, "UInt", A_IsUnicode ? 0x1074 : 0x102E, "Ptr", Item, "Ptr", &LVITEM) ; LVM_SETITEMTEXT
}
; Set the edit's position and size
EX := This.CX + This.Indent
, EY := This.CY - (This.OSVersion < 6 ? 1 : 0) ; subtract 1 for WinXP
If (This.UseColumnWidth)
EW := This.CR - EX
Else
EW := DllCall("SendMessage", "Ptr", H, "UInt", A_IsUnicode ? 0x1057 : 0x1011, "Ptr", 0, "Ptr", &ItemText, "Int") ; LVM_GETSTRINGWIDTH
, EW += This.ExtW
, EW := EW < This.MinW ? This.MinW : EW
EH := This.CH + (This.OSVersion < 6 ? 3 : 0) ; add 3 for WinXP
; Check the column alignment
If (Subitem > 0) {
VarSetCapacity(LVCOL, 56, 0)
, NumPut(1, LVCOL, "UInt") ; LVCF_FMT
, DllCall("SendMessage", "Ptr", H, "UInt", A_IsUnicode ? 0x105F : 0x1019, "Ptr", Subitem, "Ptr", &LVCOL) ; LVM_GETCOLUMN
If (This.Center := NumGet(LVCOL, 4, "UInt") & 0x0002) ; LVCFMT_CENTER
If (This.UseColumnWidth)
Control, Style, +0x0001, , % "ahk_id " . This.HEDT
Else If (ER := EX + EW) < (CR := This.CX + This.CW)
EX += ((CR - ER) // 2) + This.Indent
}
EW := (EX + EW) > This.ClientW ? This.ClientW - EX : EW
This.EX := EX, This.EY := EY, This.EW := EW, This.EH := EH
; Register WM_COMMAND handler
This.CommandFunc := ObjBindMethod(This, "On_WM_COMMAND")
, OnMessage(0x0111, This.CommandFunc)
; Register hotkeys
If !(This.Next)
This.RegisterHotkeys()
This.Cancelled := False
This.Next := False
Return False
}
; -------------------------------------------------------------------------------------------------------------------------------
; LVN_ENDLABELEDIT notification
; -------------------------------------------------------------------------------------------------------------------------------
LVN_ENDLABELEDIT(L) {
H := This.HWND, Item := This.Item, Subitem := This.Subitem, ItemText := This.ItemText
; Unregister WM_COMMAND handler
OnMessage(0x0111, This.CommandFunc, 0)
This.CommandFunc := ""
; Unregister hotkeys
If !(This.Next)
This.RegisterHotkeys(False)
If !(This.Cancelled)
ControlGetText, ItemText, , % "ahk_id " . This.HEDT
If (ItemText <> This.ItemText) {
If !(This["Changed"])
This.Changed := []
This.Changed.Push({Row: Item + 1, Col: Subitem + 1, Txt: ItemText})
}
; Restore subitem's text if changed or blanked out
If (ItemText <> This.ItemText) || ((Subitem > 0) && (This.BlankSubitem)) {
VarSetCapacity(LVITEM, 40 + (A_PtrSize * 5), 0) ; LVITEM structure
, NumPut(Item, LVITEM, 4, "Int")
, NumPut(Subitem, LVITEM, 8, "Int")
, NumPut(&ItemText, LVITEM, 16 + A_PtrSize, "Ptr") ; pszText in LVITEM
, DllCall("SendMessage", "Ptr", H, "UInt", A_IsUnicode ? 0x1074 : 0x102E, "Ptr", Item, "Ptr", &LVITEM) ; LVM_SETITEMTEXT
}
If !(This.Next)
This.Item := This.Subitem := -1
This.Cancelled := False
This.Next := False
; Call the user function, if any
If (This.EditUserFunc)
This.EditUserFunc.Call("END", H, This.HEDT, Item + 1, Subitem + 1, ItemText)
Return False
}
; -------------------------------------------------------------------------------------------------------------------------------
; NM_DBLCLICK notification
; -------------------------------------------------------------------------------------------------------------------------------
NM_DBLCLICK(L) {
Static CBW := DllCall("GetSystemMetrics", "Int", 49, "Int")
H := This.HWND
, This.Item := This.Subitem := -1
, Item := NumGet(L + (A_PtrSize * 3), 0, "Int")
, Subitem := NumGet(L + (A_PtrSize * 3), 4, "Int")
If (This["Columns"]) && (!This["Columns", Subitem])
Return False
VarSetCapacity(RC, 16, 0)
If (Item >= 0) && (Subitem >= 0) {
This.Item := Item, This.Subitem := Subitem
If !(This.Next) {
Rows := DllCall("SendMessage", "Ptr", H, "UInt", 0x1004, "Ptr", 0, "Ptr", 0, "Int") ; LVM_GETITEMCOUNT
, This.MaxItem := Rows - 1
, Cols := DllCall("SendMessage", "Ptr", This.HHDR, "UInt", 0x1200, "Ptr", 0, "Ptr", 0, "Int") ; HDM_GETITEMCOUNT
, This.MaxSubitem := Cols - 1
, DllCall("GetClientRect", "Ptr", H, "Ptr", &RC)
, This.ClientW := NumGet(RC, 8, "Int")
, This.MinW := DllCall("SendMessage", "Ptr", H, "UInt", A_IsUnicode ? 0x1057 : 0x1011, "Ptr", 0, "Str", "WWW", "Int") ; LVM_GETSTRINGWIDTH
, This.ExtW := DllCall("SendMessage", "Ptr", H, "UInt", A_IsUnicode ? 0x1057 : 0x1011, "Ptr", 0, "Str", "III", "Int") ; LVM_GETSTRINGWIDTH
, This.Col1W := DllCall("SendMessage", "Ptr", H, "UInt", 0x101D, "Ptr", 0, "Ptr", 0, "Int") ; LVM_GETCOLUMNWIDTH
, This.Checked := DllCall("SendMessage", "Ptr", H, "UInt", 0x1037, "Ptr", 0, "Ptr", 0, "UInt") & 0x00000004 ; LVM_GETEXTENDEDLISTVIEWSTYLE
}
Numput(0, RC, "Int")
, DllCall("SendMessage", "Ptr", H, "UInt", 0x100E, "Ptr", 0, "Ptr", &RC) ; LVM_GETITEMRECT
, CX := NumGet(RC, "Int")
, NumPut(Subitem = 0 ? 2 : 1, RC, "Int")
, DllCall("SendMessage", "Ptr", H, "UInt", 0x100E, "Ptr", 0, "Ptr", &RC) ; LVM_GETITEMRECT
, This.Indent := NumGet(RC, "Int") - CX - ((Subitem > 0) && This.Checked ? CBW : 0)
, NumPut(0, RC, "Int")
, NumPut(Subitem, RC, 4, "Int")
, DllCall("SendMessage", "Ptr", H, "UInt", 0x1038, "Ptr", Item, "Ptr", &RC) ; LVM_GETSUBITEMRECT
, CX := NumGet(RC, 0, "Int"), CY := NumGet(RC, 4, "Int")
, CR := (Subitem = 0 ? CX + This.Col1W : NumGet(RC, 8, "Int"))
, CW := (Subitem = 0 ? This.Col1W : CR - CX), CH := NumGet(RC, 12, "Int") - CY
ScrollH := 0
If (CX < 0) || This.ScrollToLeft
ScrollH := CX
Else If ((CX + CW) > This.ClientW) {
ScrollH := CX + CW - This.ClientW
If (ScrollH > CX)
ScrollH := CX
}
If (ScrollH)
DllCall("SendMessage", "Ptr", H, "UInt", 0x1014, "Ptr", ScrollH, "Ptr", 0) ; LVM_SCROLL
This.CX := CX - ScrollH, This.CY := CY, This.CW := CW, This.CH := CH, This.CR := CR - ScrollH
DllCall("PostMessage", "Ptr", H, "UInt", A_IsUnicode ? 0x1076 : 0x1017, "Ptr", Item, "Ptr", 0) ; LVM_EDITLABEL
}
Return False
}
; -------------------------------------------------------------------------------------------------------------------------------
; Next subitem
; -------------------------------------------------------------------------------------------------------------------------------
NextSubitem(K) {
; Hotkeys: 0x8009 (Tab -> right), 0x8409 (Shift+Tab -> left), 0x8028 (Down -> down), 0x8026 (Up -> up)
; Find the next subitem
H := This.HWND
Item := This.Item
Subitem := This.Subitem
If (K = 0x8028) || (K = 0x8026) ; down || up
Item += (K = 0x8028) ? 1 : -1
Else { ; left || right
Next := (K = 0x8409) ? -1 : 1
Loop {
Subitem += Next
If (This["Columns"]) {
If (Subitem < This.Columns.MinIndex())
Subitem := This.Columns.MaxIndex(), Item--
Else If (Subitem > This.Columns.MaxIndex())
Subitem := This.Columns.MinIndex(), Item++
Else
While (This["Columns", Subitem] = "")
Subitem += Next
}
Else If (Subitem < 0)
SubItem := This.MaxSubitem, Item--
Else If (Subitem > This.MaxSubitem)
Subitem := 0, Item++
If (DllCall("SendMessage", "Ptr", This.HWND, "UInt", 0x101D, "Ptr", SubItem, "Ptr", 0, "Int") > 0) ; LVM_GETCOLUMNWIDTH
Break
}
}
Item := (Item > This.MaxItem) ? 0 : (Item < 0) ? This.MaxItem : Item
If (Item <> This.Item)
DllCall("SendMessage", "Ptr", H, "UInt", 0x1013, "Ptr", Item, "Ptr", 0) ; LVM_ENSUREVISIBLE
This.DoubleClick(Item, Subitem)
}
; -------------------------------------------------------------------------------------------------------------------------------
; Double Click
; -------------------------------------------------------------------------------------------------------------------------------
DoubleClick(Item, Subitem) {
If (H := This.HWND) {
VarSetCapacity(RC, 16, 0), NumPut(Subitem, RC, 4, "Int")
, DllCall("SendMessage", "Ptr", H, "UInt", 0x1038, "Ptr", Item, "Ptr", &RC) ; LVM_GETSUBITEMRECT
, Point := NumGet(RC, 0, "UShort") | (NumGet(RC, 4, "UShort") << 16)
, DllCall("SendMessage", "Ptr", H, "UInt", 0x0201, "Ptr", 0, "Ptr", POINT) ; WM_LBUTTONDOWN
, DllCall("SendMessage", "Ptr", H, "UInt", 0x0202, "Ptr", 0, "Ptr", POINT) ; WM_LBUTTONUP
, DllCall("SendMessage", "Ptr", H, "UInt", 0x0203, "Ptr", 0, "Ptr", POINT) ; WM_LBUTTONDBLCLK
, DllCall("SendMessage", "Ptr", H, "UInt", 0x0202, "Ptr", 0, "Ptr", POINT) ; WM_LBUTTONUP
}
}
; -------------------------------------------------------------------------------------------------------------------------------
; Register/UnRegister hotkeys
; -------------------------------------------------------------------------------------------------------------------------------
RegisterHotkeys(Register = True) {
; WM_HOTKEY := 0x0312, MOD_SHIFT := 0x0004
; Hotkeys: 0x801B (Esc -> cancel, 0x8009 (Tab -> right), 0x8409 (Shift+Tab -> left)
; 0x8028 (Down -> down), 0x8026 (Up -> up)
H := This.HWND
If (Register) { ; Register
DllCall("RegisterHotKey", "Ptr", H, "Int", 0x801B, "UInt", 0, "UInt", 0x1B)
, DllCall("RegisterHotKey", "Ptr", H, "Int", 0x8009, "UInt", 0, "UInt", 0x09)
, DllCall("RegisterHotKey", "Ptr", H, "Int", 0x8409, "UInt", 4, "UInt", 0x09)
, DllCall("RegisterHotKey", "Ptr", H, "Int", 0x8028, "UInt", 0, "UInt", 0x28)
, DllCall("RegisterHotKey", "Ptr", H, "Int", 0x8026, "UInt", 0, "UInt", 0x26)
, This.HotkeyFunc := ObjBindMethod(This, "On_WM_HOTKEY")
, OnMessage(0x0312, This.HotkeyFunc) ; WM_HOTKEY
}
Else { ; Unregister
DllCall("UnregisterHotKey", "Ptr", H, "Int", 0x801B)
, DllCall("UnregisterHotKey", "Ptr", H, "Int", 0x8009)
, DllCall("UnregisterHotKey", "Ptr", H, "Int", 0x8409)
, DllCall("UnregisterHotKey", "Ptr", H, "Int", 0x8028)
, DllCall("UnregisterHotKey", "Ptr", H, "Int", 0x8026)
, OnMessage(0x0312, This.HotkeyFunc, 0) ; WM_HOTKEY
, This.HotkeyFunc := ""
}
}
}
代码使用就是:ICELV2 := New LV_InCellEdit(listviewID, True)