Sign in to follow this  
Followers 0
pdm

editable ListView

10 posts in this topic

#1 ·  Posted (edited)

Obviously there is no real solution for an editable ListView for AutoIt in this Forum or elsewhere.

I could find only half-cooked things all around. Editing only the first column is not that amazing! There are nice grids made from a series of inputboxes but they are very slow when scrolling through a certain amount of lines or columns. Using the Office Web Connector OWC seems to be fine, but requires a valid licence from M$.

Since i needed a Listview where all cells can be modified, i made some efforts in using a wandering inputbox on top of a standard ListView. And it works fine (with some restrictions though).

Some problems had to be solved with scrolling through the embedded scrollbars and with changing the columnwidth in the header.

A bunch of events, notifications and messages had to be taken under control, to close and reopen the editbox after the GUI changes.

The most complex "hack" has to do with the scrollbars, which appear when the resulting space for the datacells is not big enough. When the horizontal bar appears, it will automatically reduce the number of displayed lines and forces the vertical bar to appear also. I couldn't find any information whether the one or the other scrollbar is present at all, so i fixed ("a weak fix") it by computing the number of displayed rows and columns and the probability that the bars are there or not. Another solution for this can be the detection of the background-colors on the right hand side of the ListView box. When this is not equal to the left hand side, there must be a scrollbar. Possibly this is not that weak as the assumption-computation, because the dimensions of the scrollbars depend on the users Windows configuration (XP-scheme or not, width of scrollbars, ...).

I decided to offer and dedicate the work of several weeks to the people in the forum, since i could also benefit from the code of others.

And please, i know that there is someone who knows a better way to manage some of this stuff, let us all know it! Especially if you know how to "see" the scrollbars and the resulting datacell area.

Edit: 2007/03/29 Code Updated to version 0.4.

;ELV - Editable ListView
;8o) pdm V0.4 2007/03/29

#include <GUIConstants.au3>
#include <GuiListview.au3>
#include <GUICombo.au3>

Local Const $WM_NOTIFY = 0x004E
Local Const $NM_FIRST = 0
Local Const $NM_CLICK = ($NM_FIRST - 2)
Local Const $NM_DBLCLK = ($NM_FIRST - 3)

Opt("MustDeclareVars", 1)
Opt("GUICloseOnESC", 0)

;The data can be defined by the real application, but then it must be a global reference there.
;Something has to be done with the data, but this is defined by the application, not by the ELV.
;Too bad, that there are no data pointers in AutoIt! Then it could be passed to elv_init().
Global $elv_data[20][4] = [["Me", "1959/10/28", 10, 13.5], ["You", "2009/1/12", 12, 27.8], ["her", "1991/8/26", 17, 17.17], ["him", "1995/7/17", 9, 9.9], _
                           ["she", "1957/11/1", 8, 8.8], ["it", "1997/7/6", 7, 7.7], ["dau", "2011/10/28", 6, 6.6], ["dummy", "2007/3/29", 5, 5.5]]

Global $elv_edit_func[4] = ["l_elv_edit_box", "l_elv_dialogue", "l_elv_combo_box", "l_elv_monthcalendar"]

#include "dialogue.au3"

Local $elv_listview, $inb_elv, $cmb_elv, $cal_elv, $lbl_zero, $Form1
Local $open = 0, $mouse_click = False
Local $editfield_on
Local $current_col = -1, $clicked_col = 0
Local $current_x = 0, $current_y = 0
Local $current_row = -1

Local $last_row, $last_col
Local $b_use_dbl_click = False

Local $cbx_doubleclick

Local $countix = 0
Local $elv_dialogue_open = False

;#cs ;drop this stuff when you use it in a real application
main ()


Func main ()
    Local $msg, $str
    

#Region ### START Koda GUI section ### Form=T:\_au3\test\EditableListView\EditableListView.kxf
Global $Form1 = GUICreate("ELV - Editable ListView 8o) pdm", 393, 350, 303, 219, BitOR($WS_MAXIMIZEBOX,$WS_MINIMIZEBOX,$WS_SIZEBOX,$WS_THICKFRAME,$WS_SYSMENU,$WS_CAPTION,$WS_OVERLAPPEDWINDOW,$WS_TILEDWINDOW,$WS_POPUPWINDOW,$WS_GROUP,$WS_TABSTOP,$WS_BORDER,$WS_CLIPSIBLINGS))
Global $ListView = GUICtrlCreateListView("Name|Birthday|Count|Startdate", 24, 24, 281, 89, BitOR($LVS_REPORT,$LVS_SINGLESEL,$LVS_SHOWSELALWAYS,$WS_CLIPSIBLINGS), BitOR($LVS_EX_GRIDLINES,$LVS_EX_FULLROWSELECT))
Global $cbx_doubleclick = GUICtrlCreateCheckbox("Use double-click", 24, 152, 113, 25, BitOR($BS_CHECKBOX,$BS_AUTOCHECKBOX,$WS_TABSTOP,$WS_CLIPSIBLINGS))
Global $lbl_zero = GUICtrlCreateLabel("", 0, 0, 4, 4)
GUISetState(@SW_SHOW)
#EndRegion ### END Koda GUI section ###

    For $l = 0 To 9
        GUICtrlCreateListViewItem ($elv_data[$l][0] & "|" & $elv_data[$l][1] & "|" & $elv_data[$l][2] & "|" & $elv_data[$l][3], $ListView)
        $last_row = $l
    Next
    $last_col = UBound($elv_data, 2) - 1
    
    GUIRegisterMsg($WM_NOTIFY, "elv_notify")
    elv_init ($Listview)
    
    GUICtrlSetData ($cmb_elv, "cats|dogs|horses|wales","horses")
    
    elv_message ($cbx_doubleclick) ;check for double-click selection
    While 1
        $msg = GUIGetMsg()
        switch $msg
            Case $GUI_EVENT_CLOSE
                ExitLoop
            case Else
                elv_message ($msg)
        EndSwitch
    WEnd
    _msg ($elv_data[0][0]&"|"&$elv_data[0][1]&"|"&$elv_data[0][2]&"|"&$elv_data[0][3], 1)
    elv_exit ($Listview)
EndFunc   ;==>main
;#ce

;keyboard-savers
Func _con($msg, $eol = @CRLF)
    ConsoleWrite($msg & $eol)
EndFunc

Func _msg($msg, $time = 0)
    MsgBox(0, "title", $msg, $time)
EndFunc

;This should be taken to GUIListView.au3
;===============================================================================
;
; Description:            _GUICtrlListViewGetSubItemRect
; Parameter(s):        $h_listview - controlID/handle
;                    $row - item index (0-based)
;                    $col - subitem index (0-based)
;                    $left - container for the left-position
;                    $top - container for the top-position
;                    $height - container for the height-position
; Requirement:            None
; Return Value(s):    the real width of the defined cell (not the visible width!)
;  User CallTip:        _GUICtrlListViewGetSubItemRect($h_listview, $row,  $col, ByRef $left, ByRef $top, ByRef $height) Retrieve the rectangle of  a cell (required: <GuiListView.au3>)
; Author(s):            pdm
; Note(s):                published on the forum on 15.3.2007
;
;===============================================================================
Func _GUICtrlListViewGetSubItemRect($h_listview, $row, $col, ByRef $left, ByRef $top, ByRef $height)
    Local $rectangle, $rv
    
    $rectangle = DllStructCreate("int;int;int;int") ;left, top, right, bottom
    DllStructSetData($rectangle, 1, $LVIR_BOUNDS)
    DllStructSetData($rectangle, 2, $col)
    If IsHWnd($h_listview) Then
        Local $a_ret = DllCall("user32.dll", "int", "SendMessage", "hwnd", $h_listview, "int", $LVM_GETSUBITEMRECT, "int", $row, "ptr", DllStructGetPtr($rectangle))
        $rv = $a_ret[0]
    Else
        $rv = GUICtrlSendMsg($h_listview, $LVM_GETSUBITEMRECT, $row, DllStructGetPtr($rectangle))
    EndIf
    $left = DllStructGetData($rectangle, 1)
    $top = DllStructGetData($rectangle, 2)
    $height = DllStructGetData($rectangle, 4) - $top
    $rectangle = 0
    Return $rv
EndFunc   ;==>_GUICtrlListViewGetSubItemRect

Func _SetCursorState($bValue = 1)
    DllCall('User32.dll', 'int', 'ShowCursor', 'int', $bValue)
EndFunc

;///////////////////////////////////////
;elv_init ()
;
;prepares the used listview and editbox.
;///////////////////////////////////////
Func elv_init ($lv)
    $elv_listview = $lv

    l_elv_edit_box  ("create")
    l_elv_combo_box ("create")
    l_elv_dialogue  ("create")
    GUISwitch ($Form1)
    l_elv_monthcalendar ("create")

    $editfield_on = GUICtrlCreateDummy()     ;generate unique code for the message handling

    l_elv_edit_quit()
EndFunc

;////////////////////////////
;elv_exit ()
;
;destroys all created objects
;////////////////////////////
Func elv_exit ($lv)
    $elv_listview = ""
    
    l_elv_edit_box  ("delete")
    l_elv_combo_box ("delete")
    l_elv_dialogue  ("delete")
    GUISwitch ($Form1)
    l_elv_monthcalendar ("delete")

    $editfield_on = ""
EndFunc

;////////////////////////////////////////////////////////
;elv_message()
;
;is called from the message-loop of the application above
;////////////////////////////////////////////////////////
func elv_message ($msg)
    Local $rv

    if $elv_dialogue_open Then
        $rv = elv_dialogue_msg ($msg)
        if $rv <> $msg Then
            if $rv = 0 Then
                _con ("cal quit")
                l_elv_edit_quit ()
            Else
                _con ("cal save")
                l_elv_edit_save ()
            EndIf
            return
        EndIf
    Endif
    Switch $msg
        Case $cbx_doubleclick
            if GUICtrlRead ($msg) = $GUI_UNCHECKED Then
                $b_use_dbl_click = False
            Else
                $b_use_dbl_click = True
            EndIf
        Case $elv_listview
            ;_con ("lv-msg")
        Case $inb_elv, $cmb_elv, $cal_elv
            ;_con ("edit-msg")
            l_elv_edit_save()
        Case $editfield_on
            l_elv_edit_on()
        Case 0, -7, -8, -11, -12
        Case Else
            _con("msg=" & $msg);
    EndSwitch
EndFunc

;/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
;elv_notify()
;
;is  called from the applications notification function or can be registered  with GUIRegisterMsg($WM_NOTIFY, "elv_notify") directly
;/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Func elv_notify ($hWndGUI, $MsgID, $wParam, $lParam)
    #forceref $hWndGUI, $MsgID, $wParam
    Local $tagNMHDR, $event, $tagNMITEMACTIVATE, $rv

    $rv = $GUI_RUNDEFMSG
    $tagNMHDR = DllStructCreate("int;int;int", $lParam);NMHDR (hwndFrom, idFrom, code)
    If @error Then Return
    $event = DllStructGetData($tagNMHDR, 3)
    $rv = 0
    Switch $wParam
        Case $elv_listview
            Switch $event
                Case $NM_CLICK
                    l_elv_ListView_Click($elv_listview)
                Case $NM_DBLCLK
                    l_elv_ListView_DoubleClick($elv_listview)
                Case -121 ;click inside the listview data area
                    $tagNMITEMACTIVATE = DllStructCreate("int;int;int;int;int;int;int;int;int", $lParam)
                    $clicked_col = DllStructGetData($tagNMITEMACTIVATE, 5)
                    $tagNMITEMACTIVATE = 0
                Case - 108, -177, -180, -181 ;header-click, horizontal scroll, vertical scroll up and down
                    l_elv_edit_save()
                Case Else
                    ;_con ("lvw evnt="& $event)
            EndSwitch
        Case $inb_elv
            Switch $event
                Case 0
                Case Else
                    ;_con ("inb evnt="& $event)
                EndSwitch
        case $cal_elv
            _con ("cal evnt="& $event)
        Case Else
            Switch $event
                Case - 322, -328 ;changes in column width
                    l_elv_edit_save()
                Case Else
                    _con ("ctrl "& $hWndGUI &" evnt="& $event)
            EndSwitch
    EndSwitch
    $tagNMHDR = 0
    $event = 0
    $lParam = 0
    Return $rv
EndFunc

;///////////////////////////
;l_elv_edit_box()
;
;use an inputbox for editing
;///////////////////////////
func l_elv_edit_box ($cmd, $left_col = 0, $top_row = 0, $width = 0, $height = 0)
    switch $cmd
        case "create"
            $inb_elv = GUICtrlCreateInput ("", 0, 0, 0, 0, BitOR($ES_AUTOHSCROLL,$ES_NOHIDESEL,$WS_BORDER), 0)
            GUICtrlSetState ($inb_elv, $GUI_HIDE)
            GUICtrlSetBkColor($inb_elv, 0xC0DCC0)
        case "delete"
            $inb_elv = ""
        case "pos"
;            _GUICtrlListViewSetItemSelState($elv_listview, $current_row, 1, 0)
            GUICtrlSetPos ($inb_elv, $left_col + 4, $top_row + 4, $width, $height)
        case "hide"
            HotKeySet("{Enter}")
            HotKeySet("{TAB}")
            HotKeySet("+{TAB}")
            HotKeySet("{DOWN}")
            HotKeySet("{UP}")
            HotKeySet("{ESC}")
            GUICtrlSetState ($inb_elv, $GUI_HIDE)
        case "show"
            GUICtrlSetState ($inb_elv, $GUI_SHOW + $GUI_ONTOP + $GUI_FOCUS)
        case "get"
            return GUICtrlRead ($inb_elv)
        case "set"
            GUICtrlSetData ($inb_elv, $elv_data[$top_row][$left_col])
            HotKeySet("{Enter}", "l_elv_edit_right")
            HotKeySet("{TAB}",   "l_elv_edit_right")
            HotKeySet("+{TAB}",  "l_elv_edit_left")
            HotKeySet("{DOWN}",  "l_elv_edit_down")
            HotKeySet("{UP}",    "l_elv_edit_up")
            HotKeySet("{ESC}",   "l_elv_edit_esc")
    EndSwitch
EndFunc

;///////////////////////////
;l_elv_combo_box()
;
;use a combobox for editing
;///////////////////////////
func l_elv_combo_box ($cmd, $left_col = 0, $top_row = 0, $width = 0, $height = 0)
    Local $str, $a_xy[2]

    _con ("combo_box ("& $cmd &", "& $left_col &", "& $top_row &", "& $width &", "& $height &")")
    switch $cmd
        case "create"
            $cmb_elv = GUICtrlCreateCombo ("", 0, 0, 0, 0, BitOR($CBS_DROPDOWN,$CBS_AUTOHSCROLL,$CBS_SORT))
            GUICtrlSetState ($cmb_elv, $GUI_HIDE)
        case "delete"
            $cmb_elv = ""
        case "pos"
            GUICtrlSetPos ($cmb_elv, $left_col + 4, $top_row + 2, $width, $height)
            $mouse_click = False
        case "hide"
            HotKeySet("{Enter}")
            HotKeySet("{TAB}")
            HotKeySet("+{TAB}")
            HotKeySet("{ESC}")
            GUICtrlSetState ($cmb_elv, $GUI_HIDE)
        case "show"
            GUICtrlSetState ($cmb_elv, $GUI_SHOW + $GUI_ONTOP)
        case "get"
            return GUICtrlRead ($cmb_elv)
        case "set"
            $str = $elv_data[$top_row][$left_col]
            GUICtrlSetData ($cmb_elv, $str, $elv_data[$top_row][$left_col])
            HotKeySet("{Enter}", "l_elv_edit_right")
            HotKeySet("{TAB}",   "l_elv_edit_right")
            HotKeySet("+{TAB}",  "l_elv_edit_left")
            HotKeySet("{ESC}",   "l_elv_edit_esc")
    EndSwitch
EndFunc

;///////////////////////////////////////////
;l_elv_monthcalendar ()
;
;use a monthcalendar to enter a certain date
;///////////////////////////////////////////
func l_elv_monthcalendar ($cmd, $left_col = 0, $top_row = 0, $width = 0, $height = 0)
    Local $str, $a_xy[2]

    $countix += 1
    _con ("monthcalendar ("& $cmd &", "& $left_col &", "& $top_row &", "& $width &", "& $height &") count="& $countix)
    switch $cmd
        case "create"
            $cal_elv = GUICtrlCreateMonthCal ("1959/10/28", -10000, -10000, 170, 170) ;create outside to avoid flicker
            GUICtrlSetState ($cal_elv, $GUI_HIDE)
        case "delete"
            $cal_elv = ""
        case "pos"
            GUICtrlSetPos ($cal_elv, $left_col, $top_row)
            $mouse_click = False
        case "hide"
            HotKeySet("{Enter}")
            HotKeySet("{TAB}")
            HotKeySet("+{TAB}")
            HotKeySet("{ESC}")
            HotKeySet("{DOWN}")
            HotKeySet("{UP}")
            GUICtrlSetState ($cal_elv, $GUI_HIDE)
        case "show"
            GUICtrlSetState ($cal_elv, $GUI_SHOW + $GUI_ONTOP + $GUI_FOCUS)
            GUICtrlSetStyle ($cal_elv, -1, $WS_EX_TOPMOST)
        case "get"
            return GUICtrlRead ($cal_elv)
        case "set"
            $str = $elv_data[$top_row][$left_col]
            GUICtrlSetData ($cal_elv, $str, $elv_data[$top_row][$left_col])
            HotKeySet("{Enter}", "l_elv_edit_right")
            HotKeySet("{TAB}",   "l_elv_edit_right")
            HotKeySet("+{TAB}",  "l_elv_edit_left")
            HotKeySet("{ESC}",   "l_elv_edit_esc")
            HotKeySet("{DOWN}",  "l_elv_edit_down")
            HotKeySet("{UP}",    "l_elv_edit_up")
    EndSwitch
EndFunc

;////////////////////////
;l_elv_dialogue ()
;
;use a seperate dialogbox
;////////////////////////
func l_elv_dialogue ($cmd, $left_col = 0, $top_row = 0, $width = 0, $height = 0)
    Local $str, $a_xy[2]

    $countix += 1
    _con ("dialogue ("& $cmd &", "& $left_col &", "& $top_row &", "& $width &", "& $height &") count="& $countix)
    switch $cmd
        case "create"
            elv_dialogue ($cmd)
        case "delete"
            elv_dialogue ($cmd)
        case "pos"
            elv_dialogue ($cmd, $left_col, $top_row, $lbl_zero) ;lbl_zero must be on position 0,0 in the form containing the listview
            $mouse_click = False
        case "hide"
            HotKeySet("{Enter}")
            HotKeySet("{TAB}")
            HotKeySet("+{TAB}")
            HotKeySet("{ESC}")
            HotKeySet("{DOWN}")
            HotKeySet("{UP}")
            elv_dialogue ($cmd)
            $elv_dialogue_open = False
        case "show"
            elv_dialogue ($cmd)
            $elv_dialogue_open = True
        case "get"
            return elv_dialogue ($cmd)
        case "set"
            elv_dialogue ($cmd, $elv_data[$top_row][$left_col])
            HotKeySet("{Enter}", "l_elv_edit_right")
            HotKeySet("{TAB}",   "l_elv_edit_right")
            HotKeySet("+{TAB}",  "l_elv_edit_left")
            HotKeySet("{ESC}",   "l_elv_edit_esc")
            HotKeySet("{DOWN}",  "l_elv_edit_down")
            HotKeySet("{UP}",    "l_elv_edit_up")
    EndSwitch
EndFunc


Func l_elv_edit_save ()
    If $open = 2 Then
        ;_con ("save open="& $open)
        $elv_data[$current_row][$current_col] = call ($elv_edit_func[$current_col], "get") ;GUICtrlRead($inb_elv)
        _GUICtrlListViewSetItemText ($elv_listview, $current_row, $current_col, $elv_data[$current_row][$current_col])
        $open = 1
    EndIf
    l_elv_edit_quit ()
EndFunc   ;==>l_edit_save

Func l_elv_edit_quit ()
    If $open <> 0 Then
        ;_con ("quit open="& $open)
        call ($elv_edit_func[$current_col], "hide") ;GUICtrlSetState($inb_elv, $GUI_HIDE)
        GUICtrlSetState($elv_listview, $GUI_ONTOP + $GUI_FOCUS)
        $open = 0
    EndIf
    If $mouse_click Then
        $mouse_click = False
        if $b_use_dbl_click Then
            Local $a_xy[1]

            $a_xy = MouseGetPos ()
            MouseClick ("left", $a_xy[0], $a_xy[1], 2)
        Else
            MouseClick ("left")
        EndIf
    EndIf
EndFunc   ;==>l_edit_quit

Func l_elv_ListView_Click ($lv)
    if $b_use_dbl_click Then
        $mouse_click = False
        l_elv_edit_save ()
    Else
        l_elv_start_edit ()
    EndIf
EndFunc   ;==>ListView_Click

Func l_elv_ListView_DoubleClick ($lv)
    if $b_use_dbl_click Then
        l_elv_start_edit ()
    Else
        ;
    EndIf
EndFunc

func l_elv_start_edit ()
    ;_con ("lv click open="& $open &" clicked col="& $clicked_col)
    If $clicked_col < 0 Then
        _con("off mcl=" & $mouse_click)
        l_elv_edit_save ()
        Return
    EndIf
    If $open = 2 Then
        l_elv_edit_save ()
    ElseIf $open = 1 Then
        Return
    EndIf

    $open = 1
    $mouse_click = True
    l_elv_prepare_edit (_GUICtrlListViewGetCurSel ($elv_listview), $clicked_col)
EndFunc   ;==>ListView_DoubleClick

Func l_elv_prepare_edit ($row, $col)
    Local $left, $top, $height, $width, $lvw, $a_coord[4], $str, $shift, $colw, $rowh, $vs, $hs, $hh, $sw, $sh

    ;_con ("prepare open="& $open)
    $current_row = $row
    If $current_row < 0 Then
        ;$current_row = 0
        Return
    EndIf
    $current_col = $col
    If $current_col < 0 Then $current_col = 0
    _GUICtrlListViewEnsureVisible ($elv_listview, $current_row, 0)

    $width = _GUICtrlListViewGetColumnWidth ($elv_listview, $current_col)
    _GUICtrlListViewGetSubItemRect ($elv_listview, $current_row, $current_col, $left, $top, $height)
    $colw = $width + 2
    If $current_col = $last_col Then
        For $c = 0 To $current_col - 1
            $colw += _GUICtrlListViewGetColumnWidth ($elv_listview, $c) + 1 ;+1 for the gridline
        Next
    EndIf
    Opt("GUICoordMode", 0)
    $a_coord = ControlGetPos ("", "", $elv_listview) ;get coordinates of ListView (x, y, w, h)
    Opt("GUICoordMode", 1)
    If Not IsArray ($a_coord) Then
        Return
    EndIf
    $str = _ArrayToString ($a_coord, "/")
    $lvw = $a_coord[2] ;w

    $hh = 20
    $sw = 24
    $sh = 20
    ;Under certain conditions, vertical and/or horizontal scrollbars will be displayed.
    ;The vertical bar reduces the usable width, which can force the horizontal bar to appear.
    ;The horizontal scrollbar reduces the number of displayed lines and can force a vertical bar to be shown.
    ;These conditions will affect the editfield in the last column.
    $rowh = $last_row * ($height + 1) + ($height - 5) ;+1 for the gridline +extra for partial height of last line
    If $rowh > ($a_coord[3] - $hh) Then
        $vs = $sw ;vertical slider exists
    Else
        $vs = 0
    EndIf
    If $colw > ($a_coord[2] - $vs) Then
        $hs = $sh ;horizontal slider exists
    Else
        $hs = 0
    EndIf
    If $rowh > ($a_coord[3] - $hh - $hs + 4) Then ;+extra due to hysteresis when horizontal bar exists and vertical one still not
        $vs = $sw ;vertical slider exists
    EndIf
    ;_con  ($last_row &" rows height "& $height+1 &" *="& $rowh  &" hi="& $a_coord[3] &" vs="& $vs &" hs="& $hs)
    $lvw -= $vs ;w - sliderwidth

    $shift = 0
    If $left > $lvw Then
        If $width > $lvw Then
            $width = $lvw
            $shift = 0 - $left
            $left = 0
        Else
            $shift = $left - $lvw + $width
            $left -= $shift
        EndIf
    ElseIf $left < 0 Then
        If $width > $lvw Then
            $width = $lvw
            $shift = $left
            $left = 0
        Else
            $shift = $left
            $left = 0
        EndIf
    ElseIf $left + $width > $lvw Then
        If $width > $lvw Then
            $width = $lvw
            $shift = 0 - $left
            $left = 0
        Else
            $shift = $left - $lvw + $width
            $left -= $shift
        EndIf
    EndIf
    If $shift <> 0 Then
        _GUICtrlListViewScroll ($elv_listview, $shift, 0)
    EndIf

    ;_con  ("lv x/y/w/h="& $str &"   left="& $left &" top="&  $top &" wid="& $width &" hei="& $height &"  shift="& $shift &" lvw="& $lvw)

    _GUICtrlListViewSetItemSelState($elv_listview, $current_row, 1, 0)
    call ($elv_edit_func[$current_col], "pos", $left + $a_coord[0], $top + $a_coord[1], $width, $height) ;GUICtrlSetPos($inb_elv, $left + $a_coord[0] + 4, $top + $a_coord[1] + 5, $width, $height + 0)
    $open = 1
    GUICtrlSendToDummy ($editfield_on) ;start edit-field
EndFunc   ;==>l_prepare_edit

Func l_elv_edit_on ()
    ;_con ("on open="& $open)
    call ($elv_edit_func[$current_col], "show") ;GUICtrlSetState($inb_elv, $GUI_SHOW + $GUI_ONTOP + $GUI_FOCUS)
    call ($elv_edit_func[$current_col], "set", $current_col, $current_row) ;GUICtrlSetData($inb_elv, $elv_data[$current_row][$current_col])

    $open = 2
EndFunc   ;==>l_edit_on

func l_elv_edit_esc ()
    $mouse_click = False
    l_elv_edit_quit ()
EndFunc

Func l_elv_edit_right ()
    Local $col, $row
    
    $row = $current_row
    $col = $current_col
    If $col < $last_col Then
        $col += 1
    Else
        $col = 0
        $row += 1
    EndIf
    If $row <= $last_row Then
        l_elv_edit_save ()
        l_elv_prepare_edit ($row, $col)
    EndIf
EndFunc   ;==>l_edit_right

Func l_elv_edit_left ()
    Local $col, $row
    
    $row = $current_row
    $col = $current_col
    If $col > 0 Then
        $col -= 1
    Else
        $row -= 1
        $col = $last_col
    EndIf
    If $row >= 0 Then
        l_elv_edit_save ()
        l_elv_prepare_edit ($row, $col)
    EndIf
EndFunc   ;==>l_edit_left

Func l_elv_edit_down ()
    If $current_row < $last_row Then
        l_elv_edit_save ()
        l_elv_prepare_edit ($current_row + 1, $current_col)
    EndIf
EndFunc   ;==>l_edit_down

Func l_elv_edit_up ()
    If $current_row > 0 Then
        l_elv_edit_save ()
        l_elv_prepare_edit ($current_row - 1, $current_col)
    EndIf
EndFunc   ;==>l_edit_up

////////////////////////////////////////////////////////////////////////////////////////////////////////
  ;cut this here and put it into dialogue.au3
  \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
\\\\

Local $l_cal_on = False
Local $l_org_date = ""
Local $l_cal_id
Local $l_dia_width, $l_dia_height
Local $l_ret_empty = False

Local $btn_dia_cancel, $btn_dia_ok, $btn_dia_empty, $frm_calendar, $MonthCal1, $tab_calendar, $frm_calender

;////////////////////////////////////////////////////////////
;elv_dialogue ()
;
;is called from the column-specific function l_elv_dialogue()
;it has a variable number of arguments
;////////////////////////////////////////////////////////////
func elv_dialogue ($cmd, $arg1 = 0, $arg2 = 0, $arg3 = 0)
    Local $a_coord[4], $hwnd, $x, $y

    switch $cmd
        case "create"
            if $l_cal_on Then
                return 0
            EndIf

#Region ### START Koda GUI section ### Form=T:\_au3\test\EditableListView\dialogue.kxf
Global $frm_calendar = GUICreate("Calendar", 272, 218, 367, 236, BitOR($WS_CLIPCHILDREN,$WS_CLIPSIBLINGS), $WS_EX_TOOLWINDOW)
GUISetIcon("D:09.ico")
Global $MonthCal1 = GUICtrlCreateMonthCal("2007/03/27", 8, 8, 185, 177, -1, 0)
Global $btn_dia_cancel = GUICtrlCreateButton("X", 232, 8, 25, 25, 0)
GUICtrlSetFont(-1, 8, 800, 0, "MS Sans Serif")
Global $btn_dia_ok = GUICtrlCreateButton("OK", 208, 160, 49, 25, 0)
Global $btn_dia_empty = GUICtrlCreateButton("Empty", 208, 128, 49, 25, 0)
#EndRegion ### END Koda GUI section ###

            $l_cal_on = True
            WinMove ($frm_calendar, "", -10000, -10000) ;create outside visible area to avoid flicker
            GUISetState (@SW_SHOW)
            WinSetState ($frm_calender, "", @SW_HIDE)
            $a_coord = WinGetPos ($frm_calendar) ;to keep the dialogue completely visible, we need the real width and height
            $l_dia_width = $a_coord[2]
            $l_dia_height = $a_coord[3]

        case "delete"
            if not $l_cal_on Then
                return 0
            EndIf
            GUIDelete ($frm_calendar)
            $l_cal_on = False
        case "pos" ;arg1=left arg2=top arg3=lbl_zero
            $hwnd = ControlGetHandle ( "", "", $arg3) ;get the handle for the lbl_zero, which is at position 0,0 of the application form
            $a_coord = WinGetPos ($hwnd)    ;we need the absolute coordinates of the inner edge of the form
            $x = $a_coord[0]+ $arg1 + 4        ;add the relative x of the current listview cell
            $y = $a_coord[1] + $arg2 + 2    ;add the relative y of the current listview cell
            if $x + $l_dia_width > @DesktopWidth Then
                $x = @DesktopWidth - $l_dia_width    ;keep away from the right screen border
            EndIf
            if $y + $l_dia_height > @DesktopHeight Then
                $y = @DesktopHeight - $l_dia_height - 32 ;-32:assume visible taskbar
            EndIf
            WinMove ($frm_calendar, "", $x, $y)
            $l_ret_empty = False
        case "hide"
            WinSetState ($frm_calendar, "", @SW_HIDE)
        case "show"
            WinSetState ($frm_calendar, "", @SW_SHOW)
        case "get"
            if $l_ret_empty Then
                return ""
            EndIf
            return GUICtrlRead ($MonthCal1)
        case "set" ;arg1=date
            $l_org_date = $arg1
            GUICtrlSetData ($MonthCal1, $arg1, $arg1)
    EndSwitch
    return 0
EndFunc

;///////////////////////////////////////////////////////////////
;l_elv_dialogue_msg ()
;
;this is called from the message handler of the EditableListView
;///////////////////////////////////////////////////////////////
func elv_dialogue_msg ($msg)
    Local $rv

    switch $msg
        case $btn_dia_cancel
            $rv = 0
        case $btn_dia_ok
            $rv = 1
        case $btn_dia_empty
            $l_ret_empty = True
            $rv = 1
        case Else
            $rv = $msg
    EndSwitch
    return $rv
EndFunc

I'm still working on improvements to the code above. I want to develop a configuration for every column, which allows to take either an editbox, a combo, a calendar, fileselection or another dialog to enter data into the cells.

The whole thing is alive for me, because i'm working (more or less payed) on a management tool for a private school. There are a lot of dialogs to be developed for the various requirements. The tool is an add-on to the commercial product "Magellan", which uses FireBird as SQL-database. This is the prerequisite to run several programs or instances that share the same data. One of my modules manages the user-accounts in the ActiveDirectory automatically from a list of pupils, RTF- and Word-templates are used for mailmerge and various printed lists, and a lot of other things will follow. And all is realized with AutoIt. I love it! :)

Edited by pdm

Share this post


Link to post
Share on other sites



Wow, its realy working! (edit all columns!). Thanks!

But... maybe somehow possible make that the edit will activated on dowble click, not on the first click? (like the original way).


 

Spoiler

Using OS: Win 7 Professional, Using AutoIt Ver(s): 3.3.6.1 / 3.3.8.1

AutoIt_Rus_Community.png AutoIt Russian Community

My Work...

Spoiler

AutoIt_Icon_small.pngProjects: ATT - Application Translate Tool {new}| BlockIt - Block files & folders {new}| SIP - Selected Image Preview {new}| SISCABMAN - SciTE Abbreviations Manager {new}| AutoIt Path Switcher | AutoIt Menu for Opera! | YouTube Download Center! | Desktop Icons Restorator | Math Tasks | KeyBoard & Mouse Cleaner | CaptureIt - Capture Images Utility | CheckFileSize Program

AutoIt_Icon_small.pngUDFs: OnAutoItErrorRegister - Handle AutoIt critical errors {new}| AutoIt Syntax Highlight {new}| Opera Library! | Winamp Library | GetFolderToMenu | Custom_InputBox()! | _FileRun UDF | _CheckInput() UDF | _GUIInputSetOnlyNumbers() UDF | _FileGetValidName() UDF | _GUICtrlCreateRadioCBox UDF | _GuiCreateGrid() | _PathSplitByRegExp() | _GUICtrlListView_MoveItems - UDF | GUICtrlSetOnHover_UDF! | _ControlTab UDF! | _MouseSetOnEvent() UDF! | _ProcessListEx - UDF | GUICtrl_SetResizing - UDF! | Mod. for _IniString UDFs | _StringStripChars UDF | _ColorIsDarkShade UDF | _ColorConvertValue UDF | _GUICtrlTab_CoverBackground | CUI_App_UDF | _IncludeScripts UDF | _AutoIt3ExecuteCode | _DragList UDF | Mod. for _ListView_Progress | _ListView_SysLink | _GenerateRandomNumbers | _BlockInputEx | _IsPressedEx | OnAutoItExit Handler | _GUICtrlCreateTFLabel UDF | WinControlSetEvent UDF | Mod. for _DirGetSizeEx UDF
 
AutoIt_Icon_small.pngExamples: 
ScreenSaver Demo - Matrix included | Gui Drag Without pause the script | _WinAttach()! | Turn Off/On Monitor | ComboBox Handler Example | Mod. for "Thinking Box" | Cool "About" Box | TasksBar Imitation Demo

Like the Projects/UDFs/Examples? Please rate the topic (up-right corner of the post header: Rating AutoIt_Rating.gif)

* === My topics === *

==================================================
My_Userbar.gif
==================================================

 

 

 

AutoIt is simple, subtle, elegant. © AutoIt Team

Share this post


Link to post
Share on other sites

Wow, its realy working! (edit all columns!). Thanks!

But... maybe somehow possible make that the edit will activated on dowble click, not on the first click? (like the original way).

Hello MsCreatoR!

If you want to start the editing on a double-click basis, you have to move the code from function ListView_Click($lv) into ListView_DoubleClick($lv), but then there will be a problem with the simulated mouse-click in l_edit_quit(). This must be changed to produce a double-click, to re-enter the editfield again. I didn't test this.

Btw, who defined the original way you mentioned? In Excel, which is a de-facto standard (like OpenCalc), you simple move to a cell and start editing. I think it's obvious, that my ListView is an editable area, why should a double-click make it easier for the user?

I also thought about another way of testing the presence of the vertical scrollbar. The color-checking left and right may work, but there is another problem when all columns together are smaller than the window. The selection only covers the real columns, so that the rest of the line remains at the default background. But i'm still busy with that...

Share this post


Link to post
Share on other sites

pdm

Hi,

Btw, who defined the original way you mentioned? In Excel, which is a de-facto standard (like OpenCalc), you simple move to a cell and start editing. I think it's obvious, that my ListView is an editable area, why should a double-click make it easier for the user?

I meant the original way that in the editable mode of AutoIt's edit control (and of many windows's programs controls) ...

But if we look at the “user's convinient”, then it must be like that:

I am selecting the item, and i do not want to edit it, just want to get the selection (maby the program retrievs some info when user select the item), and if i do want edit certain item, then i click on it again and wait a few milliseconds (maybe second is fine) untill the item expanded to editable mode - this is the “convinient way” - IMHO.


 

Spoiler

Using OS: Win 7 Professional, Using AutoIt Ver(s): 3.3.6.1 / 3.3.8.1

AutoIt_Rus_Community.png AutoIt Russian Community

My Work...

Spoiler

AutoIt_Icon_small.pngProjects: ATT - Application Translate Tool {new}| BlockIt - Block files & folders {new}| SIP - Selected Image Preview {new}| SISCABMAN - SciTE Abbreviations Manager {new}| AutoIt Path Switcher | AutoIt Menu for Opera! | YouTube Download Center! | Desktop Icons Restorator | Math Tasks | KeyBoard & Mouse Cleaner | CaptureIt - Capture Images Utility | CheckFileSize Program

AutoIt_Icon_small.pngUDFs: OnAutoItErrorRegister - Handle AutoIt critical errors {new}| AutoIt Syntax Highlight {new}| Opera Library! | Winamp Library | GetFolderToMenu | Custom_InputBox()! | _FileRun UDF | _CheckInput() UDF | _GUIInputSetOnlyNumbers() UDF | _FileGetValidName() UDF | _GUICtrlCreateRadioCBox UDF | _GuiCreateGrid() | _PathSplitByRegExp() | _GUICtrlListView_MoveItems - UDF | GUICtrlSetOnHover_UDF! | _ControlTab UDF! | _MouseSetOnEvent() UDF! | _ProcessListEx - UDF | GUICtrl_SetResizing - UDF! | Mod. for _IniString UDFs | _StringStripChars UDF | _ColorIsDarkShade UDF | _ColorConvertValue UDF | _GUICtrlTab_CoverBackground | CUI_App_UDF | _IncludeScripts UDF | _AutoIt3ExecuteCode | _DragList UDF | Mod. for _ListView_Progress | _ListView_SysLink | _GenerateRandomNumbers | _BlockInputEx | _IsPressedEx | OnAutoItExit Handler | _GUICtrlCreateTFLabel UDF | WinControlSetEvent UDF | Mod. for _DirGetSizeEx UDF
 
AutoIt_Icon_small.pngExamples: 
ScreenSaver Demo - Matrix included | Gui Drag Without pause the script | _WinAttach()! | Turn Off/On Monitor | ComboBox Handler Example | Mod. for "Thinking Box" | Cool "About" Box | TasksBar Imitation Demo

Like the Projects/UDFs/Examples? Please rate the topic (up-right corner of the post header: Rating AutoIt_Rating.gif)

* === My topics === *

==================================================
My_Userbar.gif
==================================================

 

 

 

AutoIt is simple, subtle, elegant. © AutoIt Team

Share this post


Link to post
Share on other sites

Very usefull!

Woundring if you could turn this into a "include" file so you could make a editable ListView by one command.

_GUICtrlCreateEditListView :whistle:.

Anyway great job!

Share this post


Link to post
Share on other sites

Thank you for the responses!

I cannot react daily, since i'm working on this for my school. But it continues, evolves, grows, ...

I improved the editable ListView a bit. Due to the fact, that this is not the application, but part of one, i had to make the interface more clear. Function beginning with "l_" are used only locally (a "private"-scope for functions would be fine!), while the ones starting with "elv_" will form the interface to the "real" application.

Additionally, i added a configuration for every column, so that the user may choose to take a combobox in any column to enter data from a list. This is a self-learning object, it adds any manually entered value to the combo-list.

And i added an option for the fans of double-clicking (like MsCreatoR) :) .

The functions l_elv_edit_box() and l_elv_combo_box() can be use as templates for other input dialogues. Please let me know, when somebody of you adds more stuff like this. To use a certain dialogue, insert its name into $elv_edit_func[] at the column position of your choice and call it from elv_init() to "create" the resources. If you need notifications, add the required code to elv_notify() . The same applies for messaged in elv_message().

There is a problem with the combo: the box is only shown completely, after the mouse is moved. I tried to automate this, but it was not stable. Sometimes the box appeared, sometimes not, but id did every time after i moved the mouse manually. Maybe it's some timing effect. I hope that somebody is out there to help?

;ELV - Editable ListView
;8o) pdm

#include <GUIConstants.au3>
#include <GuiListview.au3>
#include <GUICombo.au3>

Local Const $WM_NOTIFY = 0x004E
Local Const $NM_FIRST = 0
Local Const $NM_CLICK = ($NM_FIRST - 2)
Local Const $NM_DBLCLK = ($NM_FIRST - 3)

Opt("MustDeclareVars", 1)
Opt("GUICloseOnESC", 0)

;The data can be defined by the real application, but then it must be a global reference there.
;Something has to be done with the data, but this is defined by the application, not by the ELV.
;Too bad, that there are no data pointers in AutoIt! Then it could be passed to elv_init().
Global $elv_data[20][3] = [["Me", 10, 13.5], ["You", 12, 27.8], ["her", 17, 17.17], ["him", 9, 9.9], ["she", 8, 8.8], ["it", 7, 7.7], ["dau", 6, 6.6], ["dummy", 5, 5.5]]

Global $elv_edit_func[3] = ["l_elv_edit_box", "l_elv_combo_box", "l_elv_edit_box"]

Local $elv_listview, $inb_elv, $cmb_elv
Local $open = 0, $mouse_click = False
Local $editfield_on
Local $current_col = -1, $clicked_col = 0
Local $current_x = 0, $current_y = 0
Local $current_row = -1

Local $last_row, $last_col
Local $b_use_dbl_click = False

Local $cbx_doubleclick

;#cs ;drop this stuff when you use it in a real application
main ()


Func main ()
    Local $msg, $str
    

#Region ### START Koda GUI section ### Form=T:\_au3\test\ListViewEdit\ListViewEdit.kxf
Global $Form1 = GUICreate("AForm1", 393, 212, 303, 219, BitOR($WS_MAXIMIZEBOX,$WS_MINIMIZEBOX,$WS_SIZEBOX,$WS_THICKFRAME,$WS_SYSMENU,$WS_CAPTION,$WS_OVERLAPPEDWINDOW,$WS_TILEDWINDOW,$WS_POPUPWINDOW,$WS_GROUP,$WS_TABSTOP,$WS_HSCROLL,$WS_VSCROLL,$WS_BORDER,$WS_CLIPSIBLINGS))
Global $ListView = GUICtrlCreateListView("Name|Rounds|Total", 24, 24, 281, 89, -1, BitOR($LVS_EX_GRIDLINES,$LVS_EX_FULLROWSELECT))
Global $cbx_doubleclick = GUICtrlCreateCheckbox("Use double-click", 24, 152, 113, 25)
GUISetState(@SW_SHOW)
#EndRegion ### END Koda GUI section ###

    For $l = 0 To 9
        GUICtrlCreateListViewItem ($elv_data[$l][0] & "|" & $elv_data[$l][1] & "|" & $elv_data[$l][2], $ListView)
        $last_row = $l
    Next
    $last_col = UBound($elv_data, 2) - 1
    
    GUIRegisterMsg($WM_NOTIFY, "elv_notify")
    elv_init ($Listview)
    
    GUICtrlSetData ($cmb_elv, "cats|dogs|horses|wales","horses")
    
    elv_message ($cbx_doubleclick) ;check for double-click selection
    While 1
        $msg = GUIGetMsg()
        switch $msg
            Case $GUI_EVENT_CLOSE
                ExitLoop
            case Else
                elv_message ($msg)
        EndSwitch
    WEnd
    _msg ($elv_data[0][0]&"|"&$elv_data[0][1]&"|"&$elv_data[0][2])
EndFunc   ;==>main
;#ce

;keyboard-savers
Func _con($msg, $eol = @CRLF)
    ConsoleWrite($msg & $eol)
EndFunc

Func _msg($msg, $time = 0)
    MsgBox(0, "title", $msg, $time)
EndFunc

;This should be taken to GUIListView.au3
;===============================================================================
;
; Description:            _GUICtrlListViewGetSubItemRect
; Parameter(s):        $h_listview - controlID/handle
;                    $row - item index (0-based)
;                    $col - subitem index (0-based)
;                    $left - container for the left-position
;                    $top - container for the top-position
;                    $height - container for the height-position
; Requirement:            None
; Return Value(s):    the real width of the defined cell (not the visible width!)
; User CallTip:        _GUICtrlListViewGetSubItemRect($h_listview, $row, $col, ByRef $left, ByRef $top, ByRef $height) Retrieve the rectangle of a cell (required: <GuiListView.au3>)
; Author(s):            pdm
; Note(s):                published on the forum on 15.3.2007
;
;===============================================================================
Func _GUICtrlListViewGetSubItemRect($h_listview, $row, $col, ByRef $left, ByRef $top, ByRef $height)
    Local $rectangle, $rv
    
    $rectangle = DllStructCreate("int;int;int;int") ;left, top, right, bottom
    DllStructSetData($rectangle, 1, $LVIR_BOUNDS)
    DllStructSetData($rectangle, 2, $col)
    If IsHWnd($h_listview) Then
        Local $a_ret = DllCall("user32.dll", "int", "SendMessage", "hwnd", $h_listview, "int", $LVM_GETSUBITEMRECT, "int", $row, "ptr", DllStructGetPtr($rectangle))
        $rv = $a_ret[0]
    Else
        $rv = GUICtrlSendMsg($h_listview, $LVM_GETSUBITEMRECT, $row, DllStructGetPtr($rectangle))
    EndIf
    $left = DllStructGetData($rectangle, 1)
    $top = DllStructGetData($rectangle, 2)
    $height = DllStructGetData($rectangle, 4) - $top
    $rectangle = 0
    Return $rv
EndFunc   ;==>_GUICtrlListViewGetSubItemRect

Func _SetCursorState($bValue = 1)
    DllCall('User32.dll', 'int', 'ShowCursor', 'int', $bValue)
EndFunc

;///////////////////////////////////////
;elv_init ()
;
;prepares the used listview and editbox.
;///////////////////////////////////////
Func elv_init ($lv)
    $elv_listview = $lv

    l_elv_edit_box  ("create")
    l_elv_combo_box ("create")

    $editfield_on = GUICtrlCreateDummy()     ;generate unique code for the message handling

    l_elv_edit_quit()
EndFunc

;////////////////////////////////////////////////////////
;elv_message()
;
;is called from the message-loop of the application above
;////////////////////////////////////////////////////////
func elv_message ($msg)
    Switch $msg
        Case $cbx_doubleclick
            if GUICtrlRead ($msg) = $GUI_UNCHECKED Then
                $b_use_dbl_click = False
            Else
                $b_use_dbl_click = True
            EndIf
        Case $elv_listview
            ;_con ("lv-msg")
        Case $inb_elv, $cmb_elv
            ;_con ("edit-msg")
            l_elv_edit_save()
        Case $editfield_on
            l_elv_edit_on()
        Case 0, -7, -8, -11, -12
        Case Else
            _con("msg=" & $msg);
    EndSwitch
EndFunc

;/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
;elv_notify()
;
;is called from the applications notification function or can be registered with GUIRegisterMsg($WM_NOTIFY, "elv_notify") directly
;/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Func elv_notify ($hWndGUI, $MsgID, $wParam, $lParam)
    #forceref $hWndGUI, $MsgID, $wParam
    Local $tagNMHDR, $event, $tagNMITEMACTIVATE, $rv

    $rv = $GUI_RUNDEFMSG
    $tagNMHDR = DllStructCreate("int;int;int", $lParam);NMHDR (hwndFrom, idFrom, code)
    If @error Then Return
    $event = DllStructGetData($tagNMHDR, 3)
    $rv = 0
    Switch $wParam
        Case $elv_listview
            Switch $event
                Case $NM_CLICK
                    l_elv_ListView_Click($elv_listview)
                Case $NM_DBLCLK
                    l_elv_ListView_DoubleClick($elv_listview)
                Case - 121 ;click inside the listview data area
                    $tagNMITEMACTIVATE = DllStructCreate("int;int;int;int;int;int;int;int;int", $lParam)
                    $clicked_col = DllStructGetData($tagNMITEMACTIVATE, 5)
                    $tagNMITEMACTIVATE = 0
                Case - 108, -177, -180, -181 ;header-click, horizontal scroll, vertical scroll up and down
                    l_elv_edit_save()
                Case Else
                    ;_con ("lvw evnt="& $event)
            EndSwitch
        Case $inb_elv
            Switch $event
                Case 0
                Case Else
                    ;_con ("inb evnt="& $event)
            EndSwitch
        Case Else
            Switch $event
                Case - 322, -328 ;changes in column width
                    l_elv_edit_save()
                Case Else
                    _con ("ctrl "& $hWndGUI &" evnt="& $event)
            EndSwitch
    EndSwitch
    $tagNMHDR = 0
    $event = 0
    $lParam = 0
    Return $rv
EndFunc

;///////////////////////////
;l_elv_edit_box()
;
;use an inputbox for editing
;///////////////////////////
func l_elv_edit_box ($cmd, $left_col = 0, $top_row = 0, $width = 0, $height = 0)
    switch $cmd
        case "create"
            $inb_elv = GUICtrlCreateInput ("", 0, 0, 0, 0, BitOR($ES_AUTOHSCROLL,$ES_NOHIDESEL,$WS_BORDER), 0)
            GUICtrlSetState ($inb_elv, $GUI_HIDE)
            GUICtrlSetBkColor($inb_elv, 0xC0DCC0)
        case "pos"
;            _GUICtrlListViewSetItemSelState($elv_listview, $current_row, 1, 0)
            GUICtrlSetPos ($inb_elv, $left_col + 4, $top_row + 4, $width, $height)
        case "hide"
            GUICtrlSetState ($inb_elv, $GUI_HIDE)
        case "show"
            GUICtrlSetState ($inb_elv, $GUI_SHOW + $GUI_ONTOP + $GUI_FOCUS)
        case "get"
            return GUICtrlRead ($inb_elv)
        case "set"
            GUICtrlSetData ($inb_elv, $elv_data[$top_row][$left_col])
    EndSwitch
EndFunc

;///////////////////////////
;l_elv_combo_box()
;
;use a combobox for editing
;///////////////////////////
func l_elv_combo_box ($cmd, $left_col = 0, $top_row = 0, $width = 0, $height = 0)
    Local $str, $a_xy[2]

    _con ("combo_box ("& $cmd &", "& $left_col &", "& $top_row &", "& $width &", "& $height &")")
    switch $cmd
        case "create"
            $cmb_elv = GUICtrlCreateCombo ("", 184, 120, 113, 25, BitOR($CBS_DROPDOWN,$CBS_AUTOHSCROLL,$CBS_SORT))
            GUICtrlSetState ($cmb_elv, $GUI_HIDE)
        case "pos"
            ;Opt ("MouseCoordMode", 2)
            ;$a_xy = MouseGetPos ()
            ;Opt ("MouseCoordMode", 1)
            ;$current_x = $a_xy[0]
            ;$current_y = $a_xy[1]
            GUICtrlSetPos ($cmb_elv, $left_col + 4, $top_row + 2, $width, $height)
            $mouse_click = False
        case "hide"
            GUICtrlSetState ($cmb_elv, $GUI_HIDE)
        case "show"
            GUICtrlSetState ($cmb_elv, $GUI_SHOW + $GUI_ONTOP)
        case "get"
            return GUICtrlRead ($cmb_elv)
        case "set"
            $str = $elv_data[$top_row][$left_col] ;&"|"& _GUICtrlComboGetList ($cmb_elv)
            GUICtrlSetData ($cmb_elv, $str, $elv_data[$top_row][$left_col])
    EndSwitch
EndFunc


Func l_elv_edit_save ()
    If $open = 2 Then
        ;_con ("save open="& $open)
        $elv_data[$current_row][$current_col] = call ($elv_edit_func[$current_col], "get") ;GUICtrlRead($inb_elv)
        _GUICtrlListViewSetItemText ($elv_listview, $current_row, $current_col, $elv_data[$current_row][$current_col])
        $open = 1
    EndIf
    l_elv_edit_quit ()
EndFunc   ;==>l_edit_save

Func l_elv_edit_quit ()
    If $open <> 0 Then
        ;_con ("quit open="& $open)
        call ($elv_edit_func[$current_col], "hide") ;GUICtrlSetState($inb_elv, $GUI_HIDE)
        GUICtrlSetState($elv_listview, $GUI_ONTOP + $GUI_FOCUS)
        $open = 0
        HotKeySet("{Enter}")
        HotKeySet("{TAB}")
        HotKeySet("+{TAB}")
        HotKeySet("{DOWN}")
        HotKeySet("{UP}")
        HotKeySet("{ESC}")
    EndIf
    If $mouse_click Then
        $mouse_click = False
        if $b_use_dbl_click Then
            Local $a_xy[1]

            $a_xy = MouseGetPos ()
            MouseClick ("left", $a_xy[0], $a_xy[1], 2)
        Else
            MouseClick ("left")
        EndIf
    EndIf
EndFunc   ;==>l_edit_quit

Func l_elv_ListView_Click ($lv)
    if $b_use_dbl_click Then
        $mouse_click = False
        l_elv_edit_save ()
    Else
        l_elv_start_edit ()
    EndIf
EndFunc   ;==>ListView_Click

Func l_elv_ListView_DoubleClick ($lv)
    if $b_use_dbl_click Then
        l_elv_start_edit ()
    Else
        ;
    EndIf
EndFunc

func l_elv_start_edit ()
    ;_con ("lv click open="& $open &" clicked col="& $clicked_col)
    If $clicked_col < 0 Then
        _con("off mcl=" & $mouse_click)
        l_elv_edit_save ()
        Return
    EndIf
    If $open = 2 Then
        l_elv_edit_save ()
    ElseIf $open = 1 Then
        Return
    EndIf

    $open = 1
    $mouse_click = True
    l_elv_prepare_edit (_GUICtrlListViewGetCurSel ($elv_listview), $clicked_col)
EndFunc   ;==>ListView_DoubleClick

Func l_elv_prepare_edit ($row, $col)
    Local $left, $top, $height, $width, $lvw, $a_coord[4], $str, $shift, $colw, $rowh, $vs, $hs, $hh, $sw, $sh

    ;_con ("prepare open="& $open)
    $current_row = $row
    If $current_row < 0 Then
        ;$current_row = 0
        Return
    EndIf
    $current_col = $col
    If $current_col < 0 Then $current_col = 0
    _GUICtrlListViewEnsureVisible ($elv_listview, $current_row, 0)

    $width = _GUICtrlListViewGetColumnWidth ($elv_listview, $current_col)
    _GUICtrlListViewGetSubItemRect ($elv_listview, $current_row, $current_col, $left, $top, $height)
    $colw = $width + 2
    If $current_col = $last_col Then
        For $c = 0 To $current_col - 1
            $colw += _GUICtrlListViewGetColumnWidth ($elv_listview, $c) + 1 ;+1 for the gridline
        Next
    EndIf
    $a_coord = ControlGetPos ("", "", $elv_listview) ;get coordinates of ListView (x, y, w, h)
    If Not IsArray ($a_coord) Then
        Return
    EndIf
    $str = _ArrayToString ($a_coord, "/")
    $lvw = $a_coord[2] ;w
    local $colorl, $colorr, $x1, $y, $x2
    
    $x1 = $a_coord[0] + 10
    $x2 = $a_coord[0] + $a_coord[2] - 10
    $y = $top + $a_coord[1] + 4
    ;_con ("lv x/y/w/h="& $str &"   left="& $left &" top="& $top &" wid="& $width &" hei="& $height &" lvw="& $lvw &" colw="& $colw)

    $hh = 20
    $sw = 24
    $sh = 20
    ;Under certain conditions, vertical and/or horizontal scrollbars will be displayed.
    ;The vertical bar reduces the usable width, which can force the horizontal bar to appear.
    ;The horizontal scrollbar reduces the number of displayed lines and can force a vertical bar to be shown.
    ;These conditions will affect the editfield in the last column.
    $rowh = $last_row * ($height + 1) + ($height - 5) ;+1 for the gridline +extra for partial height of last line
    If $rowh > ($a_coord[3] - $hh) Then
        $vs = $sw ;vertical slider exists
    Else
        $vs = 0
    EndIf
    If $colw > ($a_coord[2] - $vs) Then
        $hs = $sh ;horizontal slider exists
    Else
        $hs = 0
    EndIf
    If $rowh > ($a_coord[3] - $hh - $hs + 4) Then ;+extra due to hysteresis when horizontal bar exists and vertical one still not
        $vs = $sw ;vertical slider exists
    EndIf
    ;_con ($last_row &" rows height "& $height+1 &" *="& $rowh &" hi="& $a_coord[3] &" vs="& $vs &" hs="& $hs)
    $lvw -= $vs ;w - sliderwidth

    $shift = 0
    If $left > $lvw Then
        If $width > $lvw Then
            $width = $lvw
            $shift = 0 - $left
            $left = 0
        Else
            $shift = $left - $lvw + $width
            $left -= $shift
        EndIf
    ElseIf $left < 0 Then
        If $width > $lvw Then
            $width = $lvw
            $shift = $left
            $left = 0
        Else
            $shift = $left
            $left = 0
        EndIf
    ElseIf $left + $width > $lvw Then
        If $width > $lvw Then
            $width = $lvw
            $shift = 0 - $left
            $left = 0
        Else
            $shift = $left - $lvw + $width
            $left -= $shift
        EndIf
    EndIf
    If $shift <> 0 Then
        _GUICtrlListViewScroll ($elv_listview, $shift, 0)
    EndIf

    ;_con ("lv x/y/w/h="& $str &"   left="& $left &" top="& $top &" wid="& $width &" hei="& $height &" shift="& $shift &" lvw="& $lvw)

    _GUICtrlListViewSetItemSelState($elv_listview, $current_row, 1, 0)
    call ($elv_edit_func[$current_col], "pos", $left + $a_coord[0], $top + $a_coord[1], $width, $height) ;GUICtrlSetPos($inb_elv, $left + $a_coord[0] + 4, $top + $a_coord[1] + 5, $width, $height + 0)
    $open = 1
    GUICtrlSendToDummy ($editfield_on) ;start edit-field
EndFunc   ;==>l_prepare_edit

Func l_elv_edit_on ()
    ;_con ("on open="& $open)
    call ($elv_edit_func[$current_col], "show") ;GUICtrlSetState($inb_elv, $GUI_SHOW + $GUI_ONTOP + $GUI_FOCUS)
    call ($elv_edit_func[$current_col], "set", $current_col, $current_row) ;GUICtrlSetData($inb_elv, $elv_data[$current_row][$current_col])

    HotKeySet("{Enter}", "l_elv_edit_right")
    HotKeySet("{TAB}", "l_elv_edit_right")
    HotKeySet("+{TAB}", "l_elv_edit_left")
    HotKeySet("{DOWN}", "l_elv_edit_down")
    HotKeySet("{UP}", "l_elv_edit_up")
    HotKeySet("{ESC}", "l_elv_edit_esc")

    $open = 2
EndFunc   ;==>l_edit_on

func l_elv_edit_esc ()
    $mouse_click = False
    l_elv_edit_quit ()
EndFunc

Func l_elv_edit_right ()
    Local $col, $row
    
    $row = $current_row
    $col = $current_col
    If $col < $last_col Then
        $col += 1
    Else
        $col = 0
        $row += 1
    EndIf
    If $row <= $last_row Then
        l_elv_edit_save ()
        l_elv_prepare_edit ($row, $col)
    EndIf
EndFunc   ;==>l_edit_right

Func l_elv_edit_left ()
    Local $col, $row
    
    $row = $current_row
    $col = $current_col
    If $col > 0 Then
        $col -= 1
    Else
        $row -= 1
        $col = $last_col
    EndIf
    If $row >= 0 Then
        l_elv_edit_save ()
        l_elv_prepare_edit ($row, $col)
    EndIf
EndFunc   ;==>l_edit_left

Func l_elv_edit_down ()
    If $current_row < $last_row Then
        l_elv_edit_save ()
        l_elv_prepare_edit ($current_row + 1, $current_col)
    EndIf
EndFunc   ;==>l_edit_down

Func l_elv_edit_up ()
    If $current_row > 0 Then
        l_elv_edit_save ()
        l_elv_prepare_edit ($current_row - 1, $current_col)
    EndIf
EndFunc   ;==>l_edit_up

PS: I would like to update the code in my first post, but i there is no edit-button!?

Share this post


Link to post
Share on other sites

PS: I would like to update the code in my first post, but i there is no edit-button!?

When you loged-in, you will see this button at buttom of your post - Posted Image

 

Spoiler

Using OS: Win 7 Professional, Using AutoIt Ver(s): 3.3.6.1 / 3.3.8.1

AutoIt_Rus_Community.png AutoIt Russian Community

My Work...

Spoiler

AutoIt_Icon_small.pngProjects: ATT - Application Translate Tool {new}| BlockIt - Block files & folders {new}| SIP - Selected Image Preview {new}| SISCABMAN - SciTE Abbreviations Manager {new}| AutoIt Path Switcher | AutoIt Menu for Opera! | YouTube Download Center! | Desktop Icons Restorator | Math Tasks | KeyBoard & Mouse Cleaner | CaptureIt - Capture Images Utility | CheckFileSize Program

AutoIt_Icon_small.pngUDFs: OnAutoItErrorRegister - Handle AutoIt critical errors {new}| AutoIt Syntax Highlight {new}| Opera Library! | Winamp Library | GetFolderToMenu | Custom_InputBox()! | _FileRun UDF | _CheckInput() UDF | _GUIInputSetOnlyNumbers() UDF | _FileGetValidName() UDF | _GUICtrlCreateRadioCBox UDF | _GuiCreateGrid() | _PathSplitByRegExp() | _GUICtrlListView_MoveItems - UDF | GUICtrlSetOnHover_UDF! | _ControlTab UDF! | _MouseSetOnEvent() UDF! | _ProcessListEx - UDF | GUICtrl_SetResizing - UDF! | Mod. for _IniString UDFs | _StringStripChars UDF | _ColorIsDarkShade UDF | _ColorConvertValue UDF | _GUICtrlTab_CoverBackground | CUI_App_UDF | _IncludeScripts UDF | _AutoIt3ExecuteCode | _DragList UDF | Mod. for _ListView_Progress | _ListView_SysLink | _GenerateRandomNumbers | _BlockInputEx | _IsPressedEx | OnAutoItExit Handler | _GUICtrlCreateTFLabel UDF | WinControlSetEvent UDF | Mod. for _DirGetSizeEx UDF
 
AutoIt_Icon_small.pngExamples: 
ScreenSaver Demo - Matrix included | Gui Drag Without pause the script | _WinAttach()! | Turn Off/On Monitor | ComboBox Handler Example | Mod. for "Thinking Box" | Cool "About" Box | TasksBar Imitation Demo

Like the Projects/UDFs/Examples? Please rate the topic (up-right corner of the post header: Rating AutoIt_Rating.gif)

* === My topics === *

==================================================
My_Userbar.gif
==================================================

 

 

 

AutoIt is simple, subtle, elegant. © AutoIt Team

Share this post


Link to post
Share on other sites

When you loged-in, you will see this button at buttom of your post - Posted Image

This Edit-button is not available for me. The help pages say that this happens after a certain time has elapsed or when an administrator has not allowed me to edit my posts. I guess it's the second reason, because i'm still treated as a "newbie" :ermm: .

But there are also good news:

When i tried to add a month calendar, i saw that it's area was overwritten by the listview, while the part outside the listview area was visible. So i remembered the "Z-Order" which is responsible for the layers of objects. I searched in the forum and came to a post from "holger" in the year 2004 where he wrote about the style $WS_CLIPSIBLINGS. After a little research in the MSDN everything was clear. This style must be applied to all objects that can be covered by other objects complete or partially. Only then the objects above are not overwritten due to the WM_PAINT message. I added this constant to the listview and some other elements of my test GUI and it works!

Here is the actual code:

_linenums:0'>
;ELV - Editable ListView
;8o) pdm v0.3

#include 
#include 
#include 

Local Const $WM_NOTIFY = 0x004E
Local Const $NM_FIRST = 0
Local Const $NM_CLICK = ($NM_FIRST - 2)
Local Const $NM_DBLCLK = ($NM_FIRST - 3)

Opt("MustDeclareVars", 1)
Opt("GUICloseOnESC", 0)

;The data can be defined by the real application, but then it must be a global reference there.
;Something has to be done with the data, but this is defined by the application, not by the ELV.
;Too bad, that there are no data pointers in AutoIt! Then it could be passed to elv_init().
Global $elv_data[20][3] = [["Me", 10, 13.5], ["You", 12, 27.8], ["her", 17, 17.17], ["him", 9, 9.9], ["she", 8, 8.8], ["it", 7, 7.7], ["dau", 6, 6.6], ["dummy", 5, 5.5]]

Global $elv_edit_func[3] = ["l_elv_edit_box", "l_elv_calendar", "l_elv_combo_box"]

Local $elv_listview, $inb_elv, $cmb_elv, $cal_elv
Local $open = 0, $mouse_click = False
Local $editfield_on
Local $current_col = -1, $clicked_col = 0
Local $current_x = 0, $current_y = 0
Local $current_row = -1

Local $last_row, $last_col
Local $b_use_dbl_click = False

Local $cbx_doubleclick

Local $countix = 0

;#cs ;drop this stuff when you use it in a real application
main ()


Func main ()
    Local $msg, $str
    

#Region ### START Koda GUI section ### Form=T:\_au3\test\ListViewEdit\ListViewEdit.kxf
Global $Form1 = GUICreate("AForm1", 393, 357, 303, 219, BitOR($WS_MAXIMIZEBOX,$WS_MINIMIZEBOX,$WS_SIZEBOX,$WS_THICKFRAME,$WS_SYSMENU,$WS_CAPTION,$WS_OVERLAPPEDWINDOW,$WS_TILEDWINDOW,$WS_POPUPWINDOW,$WS_GROUP,$WS_TABSTOP,$WS_BORDER,$WS_CLIPSIBLINGS))
Global $ListView = GUICtrlCreateListView("Name|Rounds|Total", 24, 24, 281, 89, BitOR($LVS_REPORT,$LVS_SINGLESEL,$LVS_SHOWSELALWAYS,$WS_CLIPSIBLINGS), BitOR($LVS_EX_GRIDLINES,$LVS_EX_FULLROWSELECT))
Global $cbx_doubleclick = GUICtrlCreateCheckbox("Use double-click", 24, 152, 113, 25, BitOR($BS_CHECKBOX,$BS_AUTOCHECKBOX,$WS_TABSTOP,$WS_CLIPSIBLINGS))
GUISetState(@SW_SHOW)
#EndRegion ### END Koda GUI section ###

    For $l = 0 To 9
        GUICtrlCreateListViewItem ($elv_data[$l][0] & "|" & $elv_data[$l][1] & "|" & $elv_data[$l][2], $ListView)
        $last_row = $l
    Next
    $last_col = UBound($elv_data, 2) - 1
    
    GUIRegisterMsg($WM_NOTIFY, "elv_notify")
    elv_init ($Listview)
    
    GUICtrlSetData ($cmb_elv, "cats|dogs|horses|wales","horses")
    
    elv_message ($cbx_doubleclick) ;check for double-click selection
    While 1
        $msg = GUIGetMsg()
        switch $msg
            Case $GUI_EVENT_CLOSE
                ExitLoop
            case Else
                elv_message ($msg)
        EndSwitch
    WEnd
    _msg ($elv_data[0][0]&"|"&$elv_data[0][1]&"|"&$elv_data[0][2])
EndFunc   ;==>main
;#ce

;keyboard-savers
Func _con($msg, $eol = @CRLF)
    ConsoleWrite($msg & $eol)
EndFunc

Func _msg($msg, $time = 0)
    MsgBox(0, "title", $msg, $time)
EndFunc

;This should be taken to GUIListView.au3
;===============================================================================
;
; Description:          _GUICtrlListViewGetSubItemRect
; Parameter(s):     $h_listview - controlID/handle
;                   $row - item index (0-based)
;                   $col - subitem index (0-based)
;                   $left - container for the left-position
;                   $top - container for the top-position
;                   $height - container for the height-position
; Requirement:          None
; Return Value(s):  the real width of the defined cell (not the visible width!)
; User CallTip:     _GUICtrlListViewGetSubItemRect($h_listview, $row, $col, ByRef $left, ByRef $top, ByRef $height) Retrieve the rectangle of a cell (required: )
; Author(s):            pdm
; Note(s):              published on the forum on 15.3.2007
;
;===============================================================================
Func _GUICtrlListViewGetSubItemRect($h_listview, $row, $col, ByRef $left, ByRef $top, ByRef $height)
    Local $rectangle, $rv
    
    $rectangle = DllStructCreate("int;int;int;int") ;left, top, right, bottom
    DllStructSetData($rectangle, 1, $LVIR_BOUNDS)
    DllStructSetData($rectangle, 2, $col)
    If IsHWnd($h_listview) Then
        Local $a_ret = DllCall("user32.dll", "int", "SendMessage", "hwnd", $h_listview, "int", $LVM_GETSUBITEMRECT, "int", $row, "ptr", DllStructGetPtr($rectangle))
        $rv = $a_ret[0]
    Else
        $rv = GUICtrlSendMsg($h_listview, $LVM_GETSUBITEMRECT, $row, DllStructGetPtr($rectangle))
    EndIf
    $left = DllStructGetData($rectangle, 1)
    $top = DllStructGetData($rectangle, 2)
    $height = DllStructGetData($rectangle, 4) - $top
    $rectangle = 0
    Return $rv
EndFunc   ;==>_GUICtrlListViewGetSubItemRect

Func _SetCursorState($bValue = 1)
    DllCall('User32.dll', 'int', 'ShowCursor', 'int', $bValue)
EndFunc

;///////////////////////////////////////
;elv_init ()
;
;prepares the used listview and editbox.
;///////////////////////////////////////
Func elv_init ($lv)
    $elv_listview = $lv

    l_elv_edit_box  ("create")
    l_elv_combo_box ("create")
    l_elv_calendar  ("create")

    $editfield_on = GUICtrlCreateDummy()    ;generate unique code for the message handling

    l_elv_edit_quit()
EndFunc

;////////////////////////////////////////////////////////
;elv_message()
;
;is called from the message-loop of the application above
;////////////////////////////////////////////////////////
func elv_message ($msg)
    Switch $msg
        Case $cbx_doubleclick
            if GUICtrlRead ($msg) = $GUI_UNCHECKED Then
                $b_use_dbl_click = False
            Else
                $b_use_dbl_click = True
            EndIf
        Case $elv_listview
            ;_con ("lv-msg")
        Case $inb_elv, $cmb_elv, $cal_elv
            ;_con ("edit-msg")
            l_elv_edit_save()
        Case $editfield_on
            l_elv_edit_on()
        Case 0, -7, -8, -11, -12
        Case Else
            _con("msg=" & $msg);
    EndSwitch
EndFunc

;/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
;elv_notify()
;
;is called from the applications notification function or can be registered with GUIRegisterMsg($WM_NOTIFY, "elv_notify") directly
;/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Func elv_notify ($hWndGUI, $MsgID, $wParam, $lParam)
    #forceref $hWndGUI, $MsgID, $wParam
    Local $tagNMHDR, $event, $tagNMITEMACTIVATE, $rv

    $rv = $GUI_RUNDEFMSG
    $tagNMHDR = DllStructCreate("int;int;int", $lParam);NMHDR (hwndFrom, idFrom, code)
    If @error Then Return
    $event = DllStructGetData($tagNMHDR, 3)
    $rv = 0
    Switch $wParam
        Case $elv_listview
            Switch $event
                Case $NM_CLICK
                    l_elv_ListView_Click($elv_listview)
                Case $NM_DBLCLK
                    l_elv_ListView_DoubleClick($elv_listview)
                Case -121 ;click inside the listview data area
                    $tagNMITEMACTIVATE = DllStructCreate("int;int;int;int;int;int;int;int;int", $lParam)
                    $clicked_col = DllStructGetData($tagNMITEMACTIVATE, 5)
                    $tagNMITEMACTIVATE = 0
                Case - 108, -177, -180, -181 ;header-click, horizontal scroll, vertical scroll up and down
                    l_elv_edit_save()
                Case Else
                    ;_con ("lvw evnt="& $event)
            EndSwitch
        Case $inb_elv
            Switch $event
                Case 0
                Case Else
                    ;_con ("inb evnt="& $event)
                EndSwitch
        case $cal_elv
            _con ("cal evnt="& $event)
        Case Else
            Switch $event
                Case - 322, -328 ;changes in column width
                    l_elv_edit_save()
                Case Else
                    _con ("ctrl "& $hWndGUI &" evnt="& $event)
            EndSwitch
    EndSwitch
    $tagNMHDR = 0
    $event = 0
    $lParam = 0
    Return $rv
EndFunc

;///////////////////////////
;l_elv_edit_box()
;
;use an inputbox for editing
;///////////////////////////
func l_elv_edit_box ($cmd, $left_col = 0, $top_row = 0, $width = 0, $height = 0)
    switch $cmd
        case "create"
            $inb_elv = GUICtrlCreateInput ("", 0, 0, 0, 0, BitOR($ES_AUTOHSCROLL,$ES_NOHIDESEL,$WS_BORDER), 0)
            GUICtrlSetState ($inb_elv, $GUI_HIDE)
            GUICtrlSetBkColor($inb_elv, 0xC0DCC0)
        case "pos"
;           _GUICtrlListViewSetItemSelState($elv_listview, $current_row, 1, 0)
            GUICtrlSetPos ($inb_elv, $left_col + 4, $top_row + 4, $width, $height)
        case "hide"
            HotKeySet("{Enter}")
            HotKeySet("{TAB}")
            HotKeySet("+{TAB}")
            HotKeySet("{DOWN}")
            HotKeySet("{UP}")
            HotKeySet("{ESC}")
            GUICtrlSetState ($inb_elv, $GUI_HIDE)
        case "show"
            GUICtrlSetState ($inb_elv, $GUI_SHOW + $GUI_ONTOP + $GUI_FOCUS)
        case "get"
            return GUICtrlRead ($inb_elv)
        case "set"
            GUICtrlSetData ($inb_elv, $elv_data[$top_row][$left_col])
            HotKeySet("{Enter}", "l_elv_edit_right")
            HotKeySet("{TAB}",   "l_elv_edit_right")
            HotKeySet("+{TAB}",  "l_elv_edit_left")
            HotKeySet("{DOWN}",  "l_elv_edit_down")
            HotKeySet("{UP}",    "l_elv_edit_up")
            HotKeySet("{ESC}",   "l_elv_edit_esc")
    EndSwitch
EndFunc

;///////////////////////////
;l_elv_combo_box()
;
;use a combobox for editing
;///////////////////////////
func l_elv_combo_box ($cmd, $left_col = 0, $top_row = 0, $width = 0, $height = 0)
    Local $str, $a_xy[2]

    _con ("combo_box ("& $cmd &", "& $left_col &", "& $top_row &", "& $width &", "& $height &")")
    switch $cmd
        case "create"
            $cmb_elv = GUICtrlCreateCombo ("", 0, 0, 0, 0, BitOR($CBS_DROPDOWN,$CBS_AUTOHSCROLL,$CBS_SORT))
            GUICtrlSetState ($cmb_elv, $GUI_HIDE)
        case "pos"
            GUICtrlSetPos ($cmb_elv, $left_col + 4, $top_row + 2, $width, $height)
            $mouse_click = False
        case "hide"
            HotKeySet("{Enter}")
            HotKeySet("{TAB}")
            HotKeySet("+{TAB}")
            HotKeySet("{ESC}")
            GUICtrlSetState ($cmb_elv, $GUI_HIDE)
        case "show"
            GUICtrlSetState ($cmb_elv, $GUI_SHOW + $GUI_ONTOP)
        case "get"
            return GUICtrlRead ($cmb_elv)
        case "set"
            $str = $elv_data[$top_row][$left_col]
            GUICtrlSetData ($cmb_elv, $str, $elv_data[$top_row][$left_col])
            HotKeySet("{Enter}", "l_elv_edit_right")
            HotKeySet("{TAB}",   "l_elv_edit_right")
            HotKeySet("+{TAB}",  "l_elv_edit_left")
            HotKeySet("{ESC}",   "l_elv_edit_esc")
    EndSwitch
EndFunc

func l_elv_calendar ($cmd, $left_col = 0, $top_row = 0, $width = 0, $height = 0)
    Local $str, $a_xy[2]

    $countix += 1
    _con ("calendar ("& $cmd &", "& $left_col &", "& $top_row &", "& $width &", "& $height &") count="& $countix)
    switch $cmd
        case "create"
            $cal_elv = GUICtrlCreateMonthCal ("1959/10/28", 10, 10, 170, 170)
            GUICtrlSetState ($cal_elv, $GUI_HIDE)
        case "pos"
            GUICtrlSetPos ($cal_elv, $left_col, $top_row)
            $mouse_click = False
        case "hide"
            HotKeySet("{Enter}")
            HotKeySet("{TAB}")
            HotKeySet("+{TAB}")
            HotKeySet("{ESC}")
            HotKeySet("{DOWN}")
            HotKeySet("{UP}")
            GUICtrlSetState ($cal_elv, $GUI_HIDE)
        case "show"
            GUICtrlSetState ($cal_elv, $GUI_SHOW + $GUI_ONTOP + $GUI_FOCUS)
            GUICtrlSetStyle ($cal_elv, -1, $WS_EX_TOPMOST)
        case "get"
            return GUICtrlRead ($cal_elv)
        case "set"
            $str = $elv_data[$top_row][$left_col]
            GUICtrlSetData ($cal_elv, $str, $elv_data[$top_row][$left_col])
            HotKeySet("{Enter}", "l_elv_edit_right")
            HotKeySet("{TAB}",   "l_elv_edit_right")
            HotKeySet("+{TAB}",  "l_elv_edit_left")
            HotKeySet("{ESC}",   "l_elv_edit_esc")
            HotKeySet("{DOWN}",  "l_elv_edit_save")
            HotKeySet("{UP}",    "l_elv_edit_save")
    EndSwitch
EndFunc


Func l_elv_edit_save ()
    If $open = 2 Then
        ;_con ("save open="& $open)
        $elv_data[$current_row][$current_col] = call ($elv_edit_func[$current_col], "get") ;GUICtrlRead($inb_elv)
        _GUICtrlListViewSetItemText ($elv_listview, $current_row, $current_col, $elv_data[$current_row][$current_col])
        $open = 1
    EndIf
    l_elv_edit_quit ()
EndFunc   ;==>l_edit_save

Func l_elv_edit_quit ()
    If $open <> 0 Then
        ;_con ("quit open="& $open)
        call ($elv_edit_func[$current_col], "hide") ;GUICtrlSetState($inb_elv, $GUI_HIDE)
        GUICtrlSetState($elv_listview, $GUI_ONTOP + $GUI_FOCUS)
        $open = 0
    EndIf
    If $mouse_click Then
        $mouse_click = False
        if $b_use_dbl_click Then
            Local $a_xy[1]

            $a_xy = MouseGetPos ()
            MouseClick ("left", $a_xy[0], $a_xy[1], 2)
        Else
            MouseClick ("left")
        EndIf
    EndIf
EndFunc   ;==>l_edit_quit

Func l_elv_ListView_Click ($lv)
    if $b_use_dbl_click Then
        $mouse_click = False
        l_elv_edit_save ()
    Else
        l_elv_start_edit ()
    EndIf
EndFunc   ;==>ListView_Click

Func l_elv_ListView_DoubleClick ($lv)
    if $b_use_dbl_click Then
        l_elv_start_edit ()
    Else
        ;
    EndIf
EndFunc

func l_elv_start_edit ()
    ;_con ("lv click open="& $open &" clicked col="& $clicked_col)
    If $clicked_col < 0 Then
        _con("off mcl=" & $mouse_click)
        l_elv_edit_save ()
        Return
    EndIf
    If $open = 2 Then
        l_elv_edit_save ()
    ElseIf $open = 1 Then
        Return
    EndIf

    $open = 1
    $mouse_click = True
    l_elv_prepare_edit (_GUICtrlListViewGetCurSel ($elv_listview), $clicked_col)
EndFunc   ;==>ListView_DoubleClick

Func l_elv_prepare_edit ($row, $col)
    Local $left, $top, $height, $width, $lvw, $a_coord[4], $str, $shift, $colw, $rowh, $vs, $hs, $hh, $sw, $sh

    ;_con ("prepare open="& $open)
    $current_row = $row
    If $current_row < 0 Then
        ;$current_row = 0
        Return
    EndIf
    $current_col = $col
    If $current_col < 0 Then $current_col = 0
    _GUICtrlListViewEnsureVisible ($elv_listview, $current_row, 0)

    $width = _GUICtrlListViewGetColumnWidth ($elv_listview, $current_col)
    _GUICtrlListViewGetSubItemRect ($elv_listview, $current_row, $current_col, $left, $top, $height)
    $colw = $width + 2
    If $current_col = $last_col Then
        For $c = 0 To $current_col - 1
            $colw += _GUICtrlListViewGetColumnWidth ($elv_listview, $c) + 1 ;+1 for the gridline
        Next
    EndIf
    $a_coord = ControlGetPos ("", "", $elv_listview) ;get coordinates of ListView (x, y, w, h)
    If Not IsArray ($a_coord) Then
        Return
    EndIf
    $str = _ArrayToString ($a_coord, "/")
    $lvw = $a_coord[2] ;w
    local $colorl, $colorr, $x1, $y, $x2
    
    $x1 = $a_coord[0] + 10
    $x2 = $a_coord[0] + $a_coord[2] - 10
    $y = $top + $a_coord[1] + 4
    ;_con ("lv x/y/w/h="& $str &"   left="& $left &" top="& $top &" wid="& $width &" hei="& $height &" lvw="& $lvw &" colw="& $colw)

    $hh = 20
    $sw = 24
    $sh = 20
    ;Under certain conditions, vertical and/or horizontal scrollbars will be displayed.
    ;The vertical bar reduces the usable width, which can force the horizontal bar to appear.
    ;The horizontal scrollbar reduces the number of displayed lines and can force a vertical bar to be shown.
    ;These conditions will affect the editfield in the last column.
    $rowh = $last_row * ($height + 1) + ($height - 5) ;+1 for the gridline +extra for partial height of last line
    If $rowh > ($a_coord[3] - $hh) Then
        $vs = $sw ;vertical slider exists
    Else
        $vs = 0
    EndIf
    If $colw > ($a_coord[2] - $vs) Then
        $hs = $sh ;horizontal slider exists
    Else
        $hs = 0
    EndIf
    If $rowh > ($a_coord[3] - $hh - $hs + 4) Then ;+extra due to hysteresis when horizontal bar exists and vertical one still not
        $vs = $sw ;vertical slider exists
    EndIf
    ;_con ($last_row &" rows height "& $height+1 &" *="& $rowh &" hi="& $a_coord[3] &" vs="& $vs &" hs="& $hs)
    $lvw -= $vs ;w - sliderwidth

    $shift = 0
    If $left > $lvw Then
        If $width > $lvw Then
            $width = $lvw
            $shift = 0 - $left
            $left = 0
        Else
            $shift = $left - $lvw + $width
            $left -= $shift
        EndIf
    ElseIf $left < 0 Then
        If $width > $lvw Then
            $width = $lvw
            $shift = $left
            $left = 0
        Else
            $shift = $left
            $left = 0
        EndIf
    ElseIf $left + $width > $lvw Then
        If $width > $lvw Then
            $width = $lvw
            $shift = 0 - $left
            $left = 0
        Else
            $shift = $left - $lvw + $width
            $left -= $shift
        EndIf
    EndIf
    If $shift <> 0 Then
        _GUICtrlListViewScroll ($elv_listview, $shift, 0)
    EndIf

    ;_con ("lv x/y/w/h="& $str &"   left="& $left &" top="& $top &" wid="& $width &" hei="& $height &" shift="& $shift &" lvw="& $lvw)

    _GUICtrlListViewSetItemSelState($elv_listview, $current_row, 1, 0)
    call ($elv_edit_func[$current_col], "pos", $left + $a_coord[0], $top + $a_coord[1], $width, $height) ;GUICtrlSetPos($inb_elv, $left + $a_coord[0] + 4, $top + $a_coord[1] + 5, $width, $height + 0)
    $open = 1
    GUICtrlSendToDummy ($editfield_on) ;start edit-field
EndFunc   ;==>l_prepare_edit

Func l_elv_edit_on ()
    ;_con ("on open="& $open)
    call ($elv_edit_func[$current_col], "show") ;GUICtrlSetState($inb_elv, $GUI_SHOW + $GUI_ONTOP + $GUI_FOCUS)
    call ($elv_edit_func[$current_col], "set", $current_col, $current_row) ;GUICtrlSetData($inb_elv, $elv_data[$current_row][$current_col])

    $open = 2
EndFunc   ;==>l_edit_on

func l_elv_edit_esc ()
    $mouse_click = False
    l_elv_edit_quit ()
EndFunc

Func l_elv_edit_right ()
    Local $col, $row
    
    $row = $current_row
    $col = $current_col
    If $col < $last_col Then
        $col += 1
    Else
        $col = 0
        $row += 1
    EndIf
    If $row <= $last_row Then
        l_elv_edit_save ()
        l_elv_prepare_edit ($row, $col)
    EndIf
EndFunc   ;==>l_edit_right

Func l_elv_edit_left ()
    Local $col, $row
    
    $row = $current_row
    $col = $current_col
    If $col > 0 Then
        $col -= 1
    Else
        $row -= 1
        $col = $last_col
    EndIf
    If $row >= 0 Then
        l_elv_edit_save ()
        l_elv_prepare_edit ($row, $col)
    EndIf
EndFunc   ;==>l_edit_left

Func l_elv_edit_down ()
    If $current_row < $last_row Then
        l_elv_edit_save ()
        l_elv_prepare_edit ($current_row + 1, $current_col)
    EndIf
EndFunc   ;==>l_edit_down

Func l_elv_edit_up ()
    If $current_row > 0 Then
        l_elv_edit_save ()
        l_elv_prepare_edit ($current_row - 1, $current_col)
    EndIf
EndFunc   ;==>l_edit_up
I still have to find out how the calendar can be closed with the mouse. It works when you click into the visible part of the listview area or by hitting the RETURN key. A click onto a certain day causes a message, but then the user can revert a false selection only by reentering the calendar again. I think about a double-click to take the date over the listview.

The next thing i want to realize is a dialogue that allows any other form of selections. I need to have this feature to select a person from different database tables (pupils, teachers, parents, others), which requires a bit more than a combobox...

Share this post


Link to post
Share on other sites

And another version again!

Now i added a dialogue box which allows to enter a date or an empty string to get rid of one.

This is the most flexible way to enter data, because it only depends on the dialogue GUI and function what is written to the ListView cell.

Here is the actual code:

Take care! This also contains the code for dialogue.au3, the code for the entry dialogue.

You can also download the attached ZIP-file EditableListView04.zip with the .au3- and .kxf-sources.

;ELV - Editable ListView
;8o) pdm V0.4 2007/03/29

#include <GUIConstants.au3>
#include <GuiListview.au3>
#include <GUICombo.au3>

Local Const $WM_NOTIFY = 0x004E
Local Const $NM_FIRST = 0
Local Const $NM_CLICK = ($NM_FIRST - 2)
Local Const $NM_DBLCLK = ($NM_FIRST - 3)

Opt("MustDeclareVars", 1)
Opt("GUICloseOnESC", 0)

;The data can be defined by the real application, but then it must be a global reference there.
;Something has to be done with the data, but this is defined by the application, not by the ELV.
;Too bad, that there are no data pointers in AutoIt! Then it could be passed to elv_init().
Global $elv_data[20][4] = [["Me", "1959/10/28", 10, 13.5], ["You", "2009/1/12", 12, 27.8], ["her", "1991/8/26", 17, 17.17], ["him", "1995/7/17", 9, 9.9], _
                           ["she", "1957/11/1", 8, 8.8], ["it", "1997/7/6", 7, 7.7], ["dau", "2011/10/28", 6, 6.6], ["dummy", "2007/3/29", 5, 5.5]]

Global $elv_edit_func[4] = ["l_elv_edit_box", "l_elv_dialogue", "l_elv_combo_box", "l_elv_monthcalendar"]

#include "dialogue.au3"

Local $elv_listview, $inb_elv, $cmb_elv, $cal_elv, $lbl_zero, $Form1
Local $open = 0, $mouse_click = False
Local $editfield_on
Local $current_col = -1, $clicked_col = 0
Local $current_x = 0, $current_y = 0
Local $current_row = -1

Local $last_row, $last_col
Local $b_use_dbl_click = False

Local $cbx_doubleclick

Local $countix = 0
Local $elv_dialogue_open = False

;#cs ;drop this stuff when you use it in a real application
main ()


Func main ()
    Local $msg, $str
    

#Region ### START Koda GUI section ### Form=T:\_au3\test\EditableListView\EditableListView.kxf
Global $Form1 = GUICreate("ELV - Editable ListView 8o) pdm", 393, 350, 303, 219, BitOR($WS_MAXIMIZEBOX,$WS_MINIMIZEBOX,$WS_SIZEBOX,$WS_THICKFRAME,$WS_SYSMENU,$WS_CAPTION,$WS_OVERLAPPEDWINDOW,$WS_TILEDWINDOW,$WS_POPUPWINDOW,$WS_GROUP,$WS_TABSTOP,$WS_BORDER,$WS_CLIPSIBLINGS))
Global $ListView = GUICtrlCreateListView("Name|Birthday|Count|Startdate", 24, 24, 281, 89, BitOR($LVS_REPORT,$LVS_SINGLESEL,$LVS_SHOWSELALWAYS,$WS_CLIPSIBLINGS), BitOR($LVS_EX_GRIDLINES,$LVS_EX_FULLROWSELECT))
Global $cbx_doubleclick = GUICtrlCreateCheckbox("Use double-click", 24, 152, 113, 25, BitOR($BS_CHECKBOX,$BS_AUTOCHECKBOX,$WS_TABSTOP,$WS_CLIPSIBLINGS))
Global $lbl_zero = GUICtrlCreateLabel("", 0, 0, 4, 4)
GUISetState(@SW_SHOW)
#EndRegion ### END Koda GUI section ###

    For $l = 0 To 9
        GUICtrlCreateListViewItem ($elv_data[$l][0] & "|" & $elv_data[$l][1] & "|" & $elv_data[$l][2] & "|" & $elv_data[$l][3], $ListView)
        $last_row = $l
    Next
    $last_col = UBound($elv_data, 2) - 1
    
    GUIRegisterMsg($WM_NOTIFY, "elv_notify")
    elv_init ($Listview)
    
    GUICtrlSetData ($cmb_elv, "cats|dogs|horses|wales","horses")
    
    elv_message ($cbx_doubleclick) ;check for double-click selection
    While 1
        $msg = GUIGetMsg()
        switch $msg
            Case $GUI_EVENT_CLOSE
                ExitLoop
            case Else
                elv_message ($msg)
        EndSwitch
    WEnd
    _msg ($elv_data[0][0]&"|"&$elv_data[0][1]&"|"&$elv_data[0][2]&"|"&$elv_data[0][3], 1)
    elv_exit ($Listview)
EndFunc   ;==>main
;#ce

;keyboard-savers
Func _con($msg, $eol = @CRLF)
    ConsoleWrite($msg & $eol)
EndFunc

Func _msg($msg, $time = 0)
    MsgBox(0, "title", $msg, $time)
EndFunc

;This should be taken to GUIListView.au3
;===============================================================================
;
; Description:            _GUICtrlListViewGetSubItemRect
; Parameter(s):        $h_listview - controlID/handle
;                    $row - item index (0-based)
;                    $col - subitem index (0-based)
;                    $left - container for the left-position
;                    $top - container for the top-position
;                    $height - container for the height-position
; Requirement:            None
; Return Value(s):    the real width of the defined cell (not the visible width!)
; User CallTip:        _GUICtrlListViewGetSubItemRect($h_listview, $row, $col, ByRef $left, ByRef $top, ByRef $height) Retrieve the rectangle of a cell (required: <GuiListView.au3>)
; Author(s):            pdm
; Note(s):                published on the forum on 15.3.2007
;
;===============================================================================
Func _GUICtrlListViewGetSubItemRect($h_listview, $row, $col, ByRef $left, ByRef $top, ByRef $height)
    Local $rectangle, $rv
    
    $rectangle = DllStructCreate("int;int;int;int") ;left, top, right, bottom
    DllStructSetData($rectangle, 1, $LVIR_BOUNDS)
    DllStructSetData($rectangle, 2, $col)
    If IsHWnd($h_listview) Then
        Local $a_ret = DllCall("user32.dll", "int", "SendMessage", "hwnd", $h_listview, "int", $LVM_GETSUBITEMRECT, "int", $row, "ptr", DllStructGetPtr($rectangle))
        $rv = $a_ret[0]
    Else
        $rv = GUICtrlSendMsg($h_listview, $LVM_GETSUBITEMRECT, $row, DllStructGetPtr($rectangle))
    EndIf
    $left = DllStructGetData($rectangle, 1)
    $top = DllStructGetData($rectangle, 2)
    $height = DllStructGetData($rectangle, 4) - $top
    $rectangle = 0
    Return $rv
EndFunc   ;==>_GUICtrlListViewGetSubItemRect

Func _SetCursorState($bValue = 1)
    DllCall('User32.dll', 'int', 'ShowCursor', 'int', $bValue)
EndFunc

;///////////////////////////////////////
;elv_init ()
;
;prepares the used listview and editbox.
;///////////////////////////////////////
Func elv_init ($lv)
    $elv_listview = $lv

    l_elv_edit_box  ("create")
    l_elv_combo_box ("create")
    l_elv_dialogue  ("create")
    GUISwitch ($Form1)
    l_elv_monthcalendar ("create")

    $editfield_on = GUICtrlCreateDummy()     ;generate unique code for the message handling

    l_elv_edit_quit()
EndFunc

;////////////////////////////
;elv_exit ()
;
;destroys all created objects
;////////////////////////////
Func elv_exit ($lv)
    $elv_listview = ""
    
    l_elv_edit_box  ("delete")
    l_elv_combo_box ("delete")
    l_elv_dialogue  ("delete")
    GUISwitch ($Form1)
    l_elv_monthcalendar ("delete")

    $editfield_on = ""
EndFunc

;////////////////////////////////////////////////////////
;elv_message()
;
;is called from the message-loop of the application above
;////////////////////////////////////////////////////////
func elv_message ($msg)
    Local $rv

    if $elv_dialogue_open Then
        $rv = elv_dialogue_msg ($msg)
        if $rv <> $msg Then
            if $rv = 0 Then
                _con ("cal quit")
                l_elv_edit_quit ()
            Else
                _con ("cal save")
                l_elv_edit_save ()
            EndIf
            return
        EndIf
    Endif
    Switch $msg
        Case $cbx_doubleclick
            if GUICtrlRead ($msg) = $GUI_UNCHECKED Then
                $b_use_dbl_click = False
            Else
                $b_use_dbl_click = True
            EndIf
        Case $elv_listview
            ;_con ("lv-msg")
        Case $inb_elv, $cmb_elv, $cal_elv
            ;_con ("edit-msg")
            l_elv_edit_save()
        Case $editfield_on
            l_elv_edit_on()
        Case 0, -7, -8, -11, -12
        Case Else
            _con("msg=" & $msg);
    EndSwitch
EndFunc

;/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
;elv_notify()
;
;is called from the applications notification function or can be registered with GUIRegisterMsg($WM_NOTIFY, "elv_notify") directly
;/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Func elv_notify ($hWndGUI, $MsgID, $wParam, $lParam)
    #forceref $hWndGUI, $MsgID, $wParam
    Local $tagNMHDR, $event, $tagNMITEMACTIVATE, $rv

    $rv = $GUI_RUNDEFMSG
    $tagNMHDR = DllStructCreate("int;int;int", $lParam);NMHDR (hwndFrom, idFrom, code)
    If @error Then Return
    $event = DllStructGetData($tagNMHDR, 3)
    $rv = 0
    Switch $wParam
        Case $elv_listview
            Switch $event
                Case $NM_CLICK
                    l_elv_ListView_Click($elv_listview)
                Case $NM_DBLCLK
                    l_elv_ListView_DoubleClick($elv_listview)
                Case -121 ;click inside the listview data area
                    $tagNMITEMACTIVATE = DllStructCreate("int;int;int;int;int;int;int;int;int", $lParam)
                    $clicked_col = DllStructGetData($tagNMITEMACTIVATE, 5)
                    $tagNMITEMACTIVATE = 0
                Case - 108, -177, -180, -181 ;header-click, horizontal scroll, vertical scroll up and down
                    l_elv_edit_save()
                Case Else
                    ;_con ("lvw evnt="& $event)
            EndSwitch
        Case $inb_elv
            Switch $event
                Case 0
                Case Else
                    ;_con ("inb evnt="& $event)
                EndSwitch
        case $cal_elv
            _con ("cal evnt="& $event)
        Case Else
            Switch $event
                Case - 322, -328 ;changes in column width
                    l_elv_edit_save()
                Case Else
                    _con ("ctrl "& $hWndGUI &" evnt="& $event)
            EndSwitch
    EndSwitch
    $tagNMHDR = 0
    $event = 0
    $lParam = 0
    Return $rv
EndFunc

;///////////////////////////
;l_elv_edit_box()
;
;use an inputbox for editing
;///////////////////////////
func l_elv_edit_box ($cmd, $left_col = 0, $top_row = 0, $width = 0, $height = 0)
    switch $cmd
        case "create"
            $inb_elv = GUICtrlCreateInput ("", 0, 0, 0, 0, BitOR($ES_AUTOHSCROLL,$ES_NOHIDESEL,$WS_BORDER), 0)
            GUICtrlSetState ($inb_elv, $GUI_HIDE)
            GUICtrlSetBkColor($inb_elv, 0xC0DCC0)
        case "delete"
            $inb_elv = ""
        case "pos"
;            _GUICtrlListViewSetItemSelState($elv_listview, $current_row, 1, 0)
            GUICtrlSetPos ($inb_elv, $left_col + 4, $top_row + 4, $width, $height)
        case "hide"
            HotKeySet("{Enter}")
            HotKeySet("{TAB}")
            HotKeySet("+{TAB}")
            HotKeySet("{DOWN}")
            HotKeySet("{UP}")
            HotKeySet("{ESC}")
            GUICtrlSetState ($inb_elv, $GUI_HIDE)
        case "show"
            GUICtrlSetState ($inb_elv, $GUI_SHOW + $GUI_ONTOP + $GUI_FOCUS)
        case "get"
            return GUICtrlRead ($inb_elv)
        case "set"
            GUICtrlSetData ($inb_elv, $elv_data[$top_row][$left_col])
            HotKeySet("{Enter}", "l_elv_edit_right")
            HotKeySet("{TAB}",   "l_elv_edit_right")
            HotKeySet("+{TAB}",  "l_elv_edit_left")
            HotKeySet("{DOWN}",  "l_elv_edit_down")
            HotKeySet("{UP}",    "l_elv_edit_up")
            HotKeySet("{ESC}",   "l_elv_edit_esc")
    EndSwitch
EndFunc

;///////////////////////////
;l_elv_combo_box()
;
;use a combobox for editing
;///////////////////////////
func l_elv_combo_box ($cmd, $left_col = 0, $top_row = 0, $width = 0, $height = 0)
    Local $str, $a_xy[2]

    _con ("combo_box ("& $cmd &", "& $left_col &", "& $top_row &", "& $width &", "& $height &")")
    switch $cmd
        case "create"
            $cmb_elv = GUICtrlCreateCombo ("", 0, 0, 0, 0, BitOR($CBS_DROPDOWN,$CBS_AUTOHSCROLL,$CBS_SORT))
            GUICtrlSetState ($cmb_elv, $GUI_HIDE)
        case "delete"
            $cmb_elv = ""
        case "pos"
            GUICtrlSetPos ($cmb_elv, $left_col + 4, $top_row + 2, $width, $height)
            $mouse_click = False
        case "hide"
            HotKeySet("{Enter}")
            HotKeySet("{TAB}")
            HotKeySet("+{TAB}")
            HotKeySet("{ESC}")
            GUICtrlSetState ($cmb_elv, $GUI_HIDE)
        case "show"
            GUICtrlSetState ($cmb_elv, $GUI_SHOW + $GUI_ONTOP)
        case "get"
            return GUICtrlRead ($cmb_elv)
        case "set"
            $str = $elv_data[$top_row][$left_col]
            GUICtrlSetData ($cmb_elv, $str, $elv_data[$top_row][$left_col])
            HotKeySet("{Enter}", "l_elv_edit_right")
            HotKeySet("{TAB}",   "l_elv_edit_right")
            HotKeySet("+{TAB}",  "l_elv_edit_left")
            HotKeySet("{ESC}",   "l_elv_edit_esc")
    EndSwitch
EndFunc

;///////////////////////////////////////////
;l_elv_monthcalendar ()
;
;use a monthcalendar to enter a certain date
;///////////////////////////////////////////
func l_elv_monthcalendar ($cmd, $left_col = 0, $top_row = 0, $width = 0, $height = 0)
    Local $str, $a_xy[2]

    $countix += 1
    _con ("monthcalendar ("& $cmd &", "& $left_col &", "& $top_row &", "& $width &", "& $height &") count="& $countix)
    switch $cmd
        case "create"
            $cal_elv = GUICtrlCreateMonthCal ("1959/10/28", -10000, -10000, 170, 170) ;create outside to avoid flicker
            GUICtrlSetState ($cal_elv, $GUI_HIDE)
        case "delete"
            $cal_elv = ""
        case "pos"
            GUICtrlSetPos ($cal_elv, $left_col, $top_row)
            $mouse_click = False
        case "hide"
            HotKeySet("{Enter}")
            HotKeySet("{TAB}")
            HotKeySet("+{TAB}")
            HotKeySet("{ESC}")
            HotKeySet("{DOWN}")
            HotKeySet("{UP}")
            GUICtrlSetState ($cal_elv, $GUI_HIDE)
        case "show"
            GUICtrlSetState ($cal_elv, $GUI_SHOW + $GUI_ONTOP + $GUI_FOCUS)
            GUICtrlSetStyle ($cal_elv, -1, $WS_EX_TOPMOST)
        case "get"
            return GUICtrlRead ($cal_elv)
        case "set"
            $str = $elv_data[$top_row][$left_col]
            GUICtrlSetData ($cal_elv, $str, $elv_data[$top_row][$left_col])
            HotKeySet("{Enter}", "l_elv_edit_right")
            HotKeySet("{TAB}",   "l_elv_edit_right")
            HotKeySet("+{TAB}",  "l_elv_edit_left")
            HotKeySet("{ESC}",   "l_elv_edit_esc")
            HotKeySet("{DOWN}",  "l_elv_edit_down")
            HotKeySet("{UP}",    "l_elv_edit_up")
    EndSwitch
EndFunc

;////////////////////////
;l_elv_dialogue ()
;
;use a seperate dialogbox
;////////////////////////
func l_elv_dialogue ($cmd, $left_col = 0, $top_row = 0, $width = 0, $height = 0)
    Local $str, $a_xy[2]

    $countix += 1
    _con ("dialogue ("& $cmd &", "& $left_col &", "& $top_row &", "& $width &", "& $height &") count="& $countix)
    switch $cmd
        case "create"
            elv_dialogue ($cmd)
        case "delete"
            elv_dialogue ($cmd)
        case "pos"
            elv_dialogue ($cmd, $left_col, $top_row, $lbl_zero) ;lbl_zero must be on position 0,0 in the form containing the listview
            $mouse_click = False
        case "hide"
            HotKeySet("{Enter}")
            HotKeySet("{TAB}")
            HotKeySet("+{TAB}")
            HotKeySet("{ESC}")
            HotKeySet("{DOWN}")
            HotKeySet("{UP}")
            elv_dialogue ($cmd)
            $elv_dialogue_open = False
        case "show"
            elv_dialogue ($cmd)
            $elv_dialogue_open = True
        case "get"
            return elv_dialogue ($cmd)
        case "set"
            elv_dialogue ($cmd, $elv_data[$top_row][$left_col])
            HotKeySet("{Enter}", "l_elv_edit_right")
            HotKeySet("{TAB}",   "l_elv_edit_right")
            HotKeySet("+{TAB}",  "l_elv_edit_left")
            HotKeySet("{ESC}",   "l_elv_edit_esc")
            HotKeySet("{DOWN}",  "l_elv_edit_down")
            HotKeySet("{UP}",    "l_elv_edit_up")
    EndSwitch
EndFunc


Func l_elv_edit_save ()
    If $open = 2 Then
        ;_con ("save open="& $open)
        $elv_data[$current_row][$current_col] = call ($elv_edit_func[$current_col], "get") ;GUICtrlRead($inb_elv)
        _GUICtrlListViewSetItemText ($elv_listview, $current_row, $current_col, $elv_data[$current_row][$current_col])
        $open = 1
    EndIf
    l_elv_edit_quit ()
EndFunc   ;==>l_edit_save

Func l_elv_edit_quit ()
    If $open <> 0 Then
        ;_con ("quit open="& $open)
        call ($elv_edit_func[$current_col], "hide") ;GUICtrlSetState($inb_elv, $GUI_HIDE)
        GUICtrlSetState($elv_listview, $GUI_ONTOP + $GUI_FOCUS)
        $open = 0
    EndIf
    If $mouse_click Then
        $mouse_click = False
        if $b_use_dbl_click Then
            Local $a_xy[1]

            $a_xy = MouseGetPos ()
            MouseClick ("left", $a_xy[0], $a_xy[1], 2)
        Else
            MouseClick ("left")
        EndIf
    EndIf
EndFunc   ;==>l_edit_quit

Func l_elv_ListView_Click ($lv)
    if $b_use_dbl_click Then
        $mouse_click = False
        l_elv_edit_save ()
    Else
        l_elv_start_edit ()
    EndIf
EndFunc   ;==>ListView_Click

Func l_elv_ListView_DoubleClick ($lv)
    if $b_use_dbl_click Then
        l_elv_start_edit ()
    Else
        ;
    EndIf
EndFunc

func l_elv_start_edit ()
    ;_con ("lv click open="& $open &" clicked col="& $clicked_col)
    If $clicked_col < 0 Then
        _con("off mcl=" & $mouse_click)
        l_elv_edit_save ()
        Return
    EndIf
    If $open = 2 Then
        l_elv_edit_save ()
    ElseIf $open = 1 Then
        Return
    EndIf

    $open = 1
    $mouse_click = True
    l_elv_prepare_edit (_GUICtrlListViewGetCurSel ($elv_listview), $clicked_col)
EndFunc   ;==>ListView_DoubleClick

Func l_elv_prepare_edit ($row, $col)
    Local $left, $top, $height, $width, $lvw, $a_coord[4], $str, $shift, $colw, $rowh, $vs, $hs, $hh, $sw, $sh

    ;_con ("prepare open="& $open)
    $current_row = $row
    If $current_row < 0 Then
        ;$current_row = 0
        Return
    EndIf
    $current_col = $col
    If $current_col < 0 Then $current_col = 0
    _GUICtrlListViewEnsureVisible ($elv_listview, $current_row, 0)

    $width = _GUICtrlListViewGetColumnWidth ($elv_listview, $current_col)
    _GUICtrlListViewGetSubItemRect ($elv_listview, $current_row, $current_col, $left, $top, $height)
    $colw = $width + 2
    If $current_col = $last_col Then
        For $c = 0 To $current_col - 1
            $colw += _GUICtrlListViewGetColumnWidth ($elv_listview, $c) + 1 ;+1 for the gridline
        Next
    EndIf
    Opt("GUICoordMode", 0)
    $a_coord = ControlGetPos ("", "", $elv_listview) ;get coordinates of ListView (x, y, w, h)
    Opt("GUICoordMode", 1)
    If Not IsArray ($a_coord) Then
        Return
    EndIf
    $str = _ArrayToString ($a_coord, "/")
    $lvw = $a_coord[2] ;w

    $hh = 20
    $sw = 24
    $sh = 20
    ;Under certain conditions, vertical and/or horizontal scrollbars will be displayed.
    ;The vertical bar reduces the usable width, which can force the horizontal bar to appear.
    ;The horizontal scrollbar reduces the number of displayed lines and can force a vertical bar to be shown.
    ;These conditions will affect the editfield in the last column.
    $rowh = $last_row * ($height + 1) + ($height - 5) ;+1 for the gridline +extra for partial height of last line
    If $rowh > ($a_coord[3] - $hh) Then
        $vs = $sw ;vertical slider exists
    Else
        $vs = 0
    EndIf
    If $colw > ($a_coord[2] - $vs) Then
        $hs = $sh ;horizontal slider exists
    Else
        $hs = 0
    EndIf
    If $rowh > ($a_coord[3] - $hh - $hs + 4) Then ;+extra due to hysteresis when horizontal bar exists and vertical one still not
        $vs = $sw ;vertical slider exists
    EndIf
    ;_con ($last_row &" rows height "& $height+1 &" *="& $rowh &" hi="& $a_coord[3] &" vs="& $vs &" hs="& $hs)
    $lvw -= $vs ;w - sliderwidth

    $shift = 0
    If $left > $lvw Then
        If $width > $lvw Then
            $width = $lvw
            $shift = 0 - $left
            $left = 0
        Else
            $shift = $left - $lvw + $width
            $left -= $shift
        EndIf
    ElseIf $left < 0 Then
        If $width > $lvw Then
            $width = $lvw
            $shift = $left
            $left = 0
        Else
            $shift = $left
            $left = 0
        EndIf
    ElseIf $left + $width > $lvw Then
        If $width > $lvw Then
            $width = $lvw
            $shift = 0 - $left
            $left = 0
        Else
            $shift = $left - $lvw + $width
            $left -= $shift
        EndIf
    EndIf
    If $shift <> 0 Then
        _GUICtrlListViewScroll ($elv_listview, $shift, 0)
    EndIf

    ;_con ("lv x/y/w/h="& $str &"   left="& $left &" top="& $top &" wid="& $width &" hei="& $height &" shift="& $shift &" lvw="& $lvw)

    _GUICtrlListViewSetItemSelState($elv_listview, $current_row, 1, 0)
    call ($elv_edit_func[$current_col], "pos", $left + $a_coord[0], $top + $a_coord[1], $width, $height) ;GUICtrlSetPos($inb_elv, $left + $a_coord[0] + 4, $top + $a_coord[1] + 5, $width, $height + 0)
    $open = 1
    GUICtrlSendToDummy ($editfield_on) ;start edit-field
EndFunc   ;==>l_prepare_edit

Func l_elv_edit_on ()
    ;_con ("on open="& $open)
    call ($elv_edit_func[$current_col], "show") ;GUICtrlSetState($inb_elv, $GUI_SHOW + $GUI_ONTOP + $GUI_FOCUS)
    call ($elv_edit_func[$current_col], "set", $current_col, $current_row) ;GUICtrlSetData($inb_elv, $elv_data[$current_row][$current_col])

    $open = 2
EndFunc   ;==>l_edit_on

func l_elv_edit_esc ()
    $mouse_click = False
    l_elv_edit_quit ()
EndFunc

Func l_elv_edit_right ()
    Local $col, $row
    
    $row = $current_row
    $col = $current_col
    If $col < $last_col Then
        $col += 1
    Else
        $col = 0
        $row += 1
    EndIf
    If $row <= $last_row Then
        l_elv_edit_save ()
        l_elv_prepare_edit ($row, $col)
    EndIf
EndFunc   ;==>l_edit_right

Func l_elv_edit_left ()
    Local $col, $row
    
    $row = $current_row
    $col = $current_col
    If $col > 0 Then
        $col -= 1
    Else
        $row -= 1
        $col = $last_col
    EndIf
    If $row >= 0 Then
        l_elv_edit_save ()
        l_elv_prepare_edit ($row, $col)
    EndIf
EndFunc   ;==>l_edit_left

Func l_elv_edit_down ()
    If $current_row < $last_row Then
        l_elv_edit_save ()
        l_elv_prepare_edit ($current_row + 1, $current_col)
    EndIf
EndFunc   ;==>l_edit_down

Func l_elv_edit_up ()
    If $current_row > 0 Then
        l_elv_edit_save ()
        l_elv_prepare_edit ($current_row - 1, $current_col)
    EndIf
EndFunc   ;==>l_edit_up

////////////////////////////////////////////////////////////////////////////////////////////////////////
  ;cut this here and put it into dialogue.au3
  \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\

Local $l_cal_on = False
Local $l_org_date = ""
Local $l_cal_id
Local $l_dia_width, $l_dia_height
Local $l_ret_empty = False

Local $btn_dia_cancel, $btn_dia_ok, $btn_dia_empty, $frm_calendar, $MonthCal1, $tab_calendar, $frm_calender

;////////////////////////////////////////////////////////////
;elv_dialogue ()
;
;is called from the column-specific function l_elv_dialogue()
;it has a variable number of arguments
;////////////////////////////////////////////////////////////
func elv_dialogue ($cmd, $arg1 = 0, $arg2 = 0, $arg3 = 0)
    Local $a_coord[4], $hwnd, $x, $y

    switch $cmd
        case "create"
            if $l_cal_on Then
                return 0
            EndIf

#Region ### START Koda GUI section ### Form=T:\_au3\test\EditableListView\dialogue.kxf
Global $frm_calendar = GUICreate("Calendar", 272, 218, 367, 236, BitOR($WS_CLIPCHILDREN,$WS_CLIPSIBLINGS), $WS_EX_TOOLWINDOW)
GUISetIcon("D:09.ico")
Global $MonthCal1 = GUICtrlCreateMonthCal("2007/03/27", 8, 8, 185, 177, -1, 0)
Global $btn_dia_cancel = GUICtrlCreateButton("X", 232, 8, 25, 25, 0)
GUICtrlSetFont(-1, 8, 800, 0, "MS Sans Serif")
Global $btn_dia_ok = GUICtrlCreateButton("OK", 208, 160, 49, 25, 0)
Global $btn_dia_empty = GUICtrlCreateButton("Empty", 208, 128, 49, 25, 0)
#EndRegion ### END Koda GUI section ###

            $l_cal_on = True
            WinMove ($frm_calendar, "", -10000, -10000) ;create outside visible area to avoid flicker
            GUISetState (@SW_SHOW)
            WinSetState ($frm_calender, "", @SW_HIDE)
            $a_coord = WinGetPos ($frm_calendar) ;to keep the dialogue completely visible, we need the real width and height
            $l_dia_width = $a_coord[2]
            $l_dia_height = $a_coord[3]

        case "delete"
            if not $l_cal_on Then
                return 0
            EndIf
            GUIDelete ($frm_calendar)
            $l_cal_on = False
        case "pos" ;arg1=left arg2=top arg3=lbl_zero
            $hwnd = ControlGetHandle ( "", "", $arg3) ;get the handle for the lbl_zero, which is at position 0,0 of the application form
            $a_coord = WinGetPos ($hwnd)    ;we need the absolute coordinates of the inner edge of the form
            $x = $a_coord[0]+ $arg1 + 4        ;add the relative x of the current listview cell
            $y = $a_coord[1] + $arg2 + 2    ;add the relative y of the current listview cell
            if $x + $l_dia_width > @DesktopWidth Then
                $x = @DesktopWidth - $l_dia_width    ;keep away from the right screen border
            EndIf
            if $y + $l_dia_height > @DesktopHeight Then
                $y = @DesktopHeight - $l_dia_height - 32 ;-32:assume visible taskbar
            EndIf
            WinMove ($frm_calendar, "", $x, $y)
            $l_ret_empty = False
        case "hide"
            WinSetState ($frm_calendar, "", @SW_HIDE)
        case "show"
            WinSetState ($frm_calendar, "", @SW_SHOW)
        case "get"
            if $l_ret_empty Then
                return ""
            EndIf
            return GUICtrlRead ($MonthCal1)
        case "set" ;arg1=date
            $l_org_date = $arg1
            GUICtrlSetData ($MonthCal1, $arg1, $arg1)
    EndSwitch
    return 0
EndFunc

;///////////////////////////////////////////////////////////////
;l_elv_dialogue_msg ()
;
;this is called from the message handler of the EditableListView
;///////////////////////////////////////////////////////////////
func elv_dialogue_msg ($msg)
    Local $rv

    switch $msg
        case $btn_dia_cancel
            $rv = 0
        case $btn_dia_ok
            $rv = 1
        case $btn_dia_empty
            $l_ret_empty = True
            $rv = 1
        case Else
            $rv = $msg
    EndSwitch
    return $rv
EndFunc

Now i'm going to make my first steps and use this ELV with my real application. If i or someone else find bugs, i will fix them in this test-version also. So please, folks, test it and give me feedback, hints, warnings or whatever is appropriate for this useful tool (from my point of view)!

Share this post


Link to post
Share on other sites

Very usefull!

Woundring if you could turn this into a "include" file so you could make a editable ListView by one command.

_GUICtrlCreateEditListView :whistle: .

Anyway great job!

Hello Mr. Zero!

There is another version of my EditableListView! (Look at the bottom of this topic, since i do not have an edit button yet...)

You asked me to put this into an "include"-file. I think this is possible, but there is a certain interface required for this. It needs init- and exit-functions and has to participate on the message and notification loops of the application above it. And there need to be some specific settings to do what the application needs it to do.

I have to go on with my payed work and already have a certain interface to the ELV, but this is not generic.

I guess, it would be wise to create a more generic one, bBut maybe there is somebody in the forum to improve this...

Share this post


Link to post
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
Sign in to follow this  
Followers 0