Jump to content

Treeview drag & drop reorder and edit example


Siao
 Share

Recommended Posts

Make sure you have v3.2.9.5 or later...

Full drag and drop reordering of items, both with images and no images. Item will be moved to InsertMark position or into drop highlighted item.

Label edit (either mouse or keyboard Enter/Esc).

Keyboard Delete to delete selected item.

Keyboard Insert to insert new item after selected item.

#include <GuiTreeView.au3>

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

$sTitle = "Treeview Drag & Drop Editing"
;Required global constants:
Global $bTreeDrag = False, $bTreeEdit = False, $hDragItem, $hTreeDragImage, $fWhere

$hGui = GUICreate($sTitle, 400, 300, -1, -1, -1, -1)

$label = GUICtrlCreateLabel("Drag and drop separate items or branches to move them." & _
                        @LF & "To start edit selected item, LMB on item or press Enter." & _
                        @LF & "To end editing, LMB outside item (apply) or Esc (cancel) / Enter (apply)." & _
                        @LF & "To insert new item press Insert, to delete existing item press Delete.", 30, 10, 340, 60)
$cTree = GUICtrlCreateTreeView(50,75,300,200,$TVS_HASBUTTONS+$TVS_HASLINES+$TVS_LINESATROOT+$TVS_EDITLABELS+$TVS_CHECKBOXES)
GUICtrlSetState(-1, $GUI_DROPACCEPTED)
$cTreeItemsStart = GUICtrlCreateDummy()
$cTreeItem_1 = GUICtrlCreateTreeViewItem("item 1", $cTree)
$cTreeItem_1a = GUICtrlCreateTreeViewItem("item 1a", $cTreeItem_1)
$cTreeItem_1b = GUICtrlCreateTreeViewItem("item 1b", $cTreeItem_1)
$cTreeItem_2 = GUICtrlCreateTreeViewItem("item 2", $cTree)
$cTreeItem_2a = GUICtrlCreateTreeViewItem("item 2a", $cTreeItem_2)
$cTreeItem_3 = GUICtrlCreateTreeViewItem("item 3", $cTree)
$cTreeItem_3a = GUICtrlCreateTreeViewItem("item 3a", $cTreeItem_3)
$cTreeItem_3a1 = GUICtrlCreateTreeViewItem("item 3a1", $cTreeItem_3a)
$cTreeItem_4 = GUICtrlCreateTreeViewItem("item 4", $cTree)
$cTreeItemsEnd = GUICtrlCreateDummy()
;treeview with images test:
;~  $hImgList = _GUIImageList_Create (16, 16)
;~  For $ii = 1 To $cTreeItemsEnd-$cTreeItemsStart
;~      _GUIImageList_AddIcon ($hImgList, "shell32.dll", 60+$ii*2)
;~  Next
;~  _GUICtrlTreeView_SetNormalImageList(GUICtrlGetHandle($cTree), $hImgList)
;~  $a = 0
;~  For $i = $cTreeItemsStart+1 To $cTreeItemsEnd-1
;~      _GUICtrlTreeView_SetImageIndex($cTree, _GUICtrlTreeView_GetItemHandle($cTree, $i), $a)
;~      _GUICtrlTreeView_SetSelectedImageIndex($cTree, _GUICtrlTreeView_GetItemHandle($cTree, $i), $a)
;~      $a += 1
;~  Next
    
$label2 = GUICtrlCreateLabel("", 50, 280, 300, 15)

GUISetOnEvent($GUI_EVENT_CLOSE, "SysEvents")
GUISetOnEvent($GUI_EVENT_MOUSEMOVE, "SysEvents")
GUISetOnEvent($GUI_EVENT_PRIMARYUP, "SysEvents")
GUIRegisterMsg($WM_NOTIFY, "On_WM_NOTIFY")

GUISetState()

While 1
    Sleep(200)
    ;add Enter, Esc, Delete and Insert key functionality to treeview edit:
    TreeKeyboardFunc($cTree)
WEnd

Func SysEvents()
    Local $hTree = GUICtrlGetHandle($cTree)
    Switch @GUI_CtrlId
        Case $GUI_EVENT_CLOSE
            Exit
        Case $GUI_EVENT_PRIMARYUP
            If $bTreeDrag Then
                _WinAPI_InvalidateRect($hTree)
                $bTreeDrag = False
                _GUIImageList_Destroy($hTreeDragImage) ;delete drag image
                _SendMessage($hTree, $TVM_SELECTITEM, $TVGN_DROPHILITE, 0) ;remove DropTarget
                _SendMessage($hTree, $TVM_SETINSERTMARK, 0, 0) ;remove InsertMark
                If (TreeItemFromPoint($hTree) = $hDragItem) Then ContinueCase
                ;move item:
                $hItem = TreeItemCopy($hTree, $hDragItem, TreeItemFromPoint($hTree), $fWhere)
                If $hItem <> 0 Then
                    _GUICtrlTreeView_SelectItem($hTree, $hItem)
                    _GUICtrlTreeView_Delete($hTree, $hDragItem)
                EndIf
            EndIf
        Case $GUI_EVENT_MOUSEMOVE
            If $bTreeDrag = False Then ContinueCase
            $aHwnd = DllCall("user32.dll", "hwnd", "WindowFromPoint", "uint", MouseGetPos(0), "uint", MouseGetPos(1))
            ;cancel drag in progress and cleanup if moved outside treeview:
            If ($aHwnd[0] <> $hTree) Then
                $bTreeDrag = False
                _WinAPI_InvalidateRect($hTree)
                _GUIImageList_Destroy($hTreeDragImage) ;delete drag image
                _SendMessage($hTree, $TVM_SELECTITEM, $TVGN_DROPHILITE, 0) ;remove DropTarget
                _SendMessage($hTree, $TVM_SETINSERTMARK, 0, 0) ;remove InsertMark
                ContinueCase
            EndIf
            $hItemHover = TreeItemFromPoint($hTree)
            If $hItemHover = 0 Then
                ;meh
            Else
                $aRect = _GUICtrlTreeView_DisplayRect($hTree, $hItemHover)
                $iTreeY = _WinAPI_GetMousePosY(True, $hTree)
                Switch $iTreeY
                    Case $aRect[1] To $aRect[1]+Int(($aRect[3]-$aRect[1])/4)
                        _SendMessage($hTree, $TVM_SELECTITEM, $TVGN_DROPHILITE, 0) ;remove DropTarget
                        _SendMessage($hTree, $TVM_SETINSERTMARK, 0, $hItemHover) ;add InsertMark before item
                        $fWhere = -1
                    Case 1+$aRect[1]+Int(($aRect[3]-$aRect[1])/3) To $aRect[1]+Int(($aRect[3]-$aRect[1])*2/3)
                        _SendMessage($hTree, $TVM_SETINSERTMARK, 0, 0) ;remove InsertMark
                        _SendMessage($hTree, $TVM_SELECTITEM, $TVGN_DROPHILITE, $hItemHover) ;add DropTarget
                        $fWhere = 0
                    Case 1+$aRect[1]+Int(($aRect[3]-$aRect[1])*2/3) To $aRect[3]
                        _SendMessage($hTree, $TVM_SELECTITEM, $TVGN_DROPHILITE, 0) ;remove DropTarget
                        _SendMessage($hTree, $TVM_SETINSERTMARK, 1, $hItemHover) ;add InsertMark after item
                        $fWhere = 1
                EndSwitch
            EndIf
            DrawDragImage($hTree, $hTreeDragImage)
    EndSwitch
EndFunc
;   TreeItemFromPoint()
;   Returns handle of tree item under mouse:
Func TreeItemFromPoint($hWnd)
    Local $tMPos = _WinAPI_GetMousePos(True, $hWnd)
    Return _GUICtrlTreeView_HitTestItem($hWnd, DllStructGetData($tMPos, 1), DllStructGetData($tMPos, 2))
EndFunc
;   TreeItemCopy()
;   Copies tree item $hItemSource and all its children to an item $hItemTarget, depending on $fDirection
;   $fDirection:
;           -1 = before $hItemTarget
;           0 = inside $hItemTarget
;           1 = after $hItemTarget
Func TreeItemCopy($hWnd, $hItemSource, $hItemTarget, $fDirection)
    ;making sure parent can't be dropped onto one of its descendants:
    $hTest = $hItemTarget
    Do
        $hTest = _GUICtrlTreeView_GetParentHandle($hWnd, $hTest)
        If $hTest = $hItemSource Then Return 0
    Until $hTest = 0
    ;create new item at determined position
    $sText = _GUICtrlTreeView_GetText($hWnd, $hItemSource)
    $hParent = _GUICtrlTreeView_GetParentHandle($hWnd, $hItemTarget)
    Switch $fDirection
        Case -1
            $hPrev = _GUICtrlTreeView_GetPrevSibling($hWnd, $hItemTarget)
            If $hPrev = 0 Then
                $hNew = _GUICtrlTreeView_AddFirst($hWnd, $hItemTarget, $sText)
            Else
                $hNew = _GUICtrlTreeView_InsertItem($hWnd, $sText, $hParent, $hPrev)
            EndIf
        Case 0
            $hNew = _GUICtrlTreeView_InsertItem($hWnd, $sText, $hItemTarget)
        Case 1
            $hNew = _GUICtrlTreeView_InsertItem($hWnd, $sText, $hParent, $hItemTarget)
        Case Else
            Return 0
    EndSwitch
    ;save item state and checkbox image if there is such
    _GUICtrlTreeView_SetState($hWnd, $hNew, _GUICtrlTreeView_GetState($hWnd, $hItemSource))
    If _GUICtrlTreeView_GetStateImageList($hWnd) <> 0 Then 
        _GUICtrlTreeView_SetStateImageIndex($hWnd, $hNew, _GUICtrlTreeView_GetStateImageIndex($hWnd, $hItemSource))
    EndIf
    ;save icon/selected image indexes
    If _GUICtrlTreeView_GetNormalImageList($hWnd) <> 0 Then
        _GUICtrlTreeView_SetImageIndex($hWnd, $hNew, _GUICtrlTreeView_GetImageIndex($hWnd, $hItemSource))
        _GUICtrlTreeView_SetSelectedImageIndex($hWnd, $hNew, _GUICtrlTreeView_GetSelectedImageIndex($hWnd, $hItemSource))
    EndIf
    ;recurse through descendants:
    $iChildCount = _GUICtrlTreeView_GetChildCount($hWnd, $hItemSource)
    If $iChildCount > 0 Then
        For $i = 0 To $iChildCount-1
            $hRecSource = _GUICtrlTreeView_GetItemByIndex($hWnd, $hItemSource, $i)
            TreeItemCopy($hWnd, $hRecSource, $hNew, 0)
        Next
    EndIf
    Return $hNew
EndFunc
Func On_WM_NOTIFY($hWnd, $Msg, $wParam, $lParam)
    ;wparam = cid, lparam = pnmh
    If $wParam = $cTree Then
        Local $tNMHDR = DllStructCreate("hwnd hTree;uint;int code", $lParam)
        Local $code = DllStructGetData($tNMHDR, "code")
        Local $hTree = HWnd(DllStructGetData($tNMHDR, "hTree"))
        Switch $code
            Case $TVN_BEGINDRAG, $TVN_BEGINDRAGW
                $bTreeDrag = True
                $hDragItem = TreeItemFromPoint($hTree)
;~              _GUICtrlTreeView_SelectItem($hTree, $hDragItem)
                _GUICtrlTreeView_SetSelected($hTree, _GUICtrlTreeView_GetSelection($hTree), False)
                $hTreeDragImage = TreeCreateDragImage($hTree, $hDragItem)
                DrawDragImage($hTree, $hTreeDragImage)
            Case $TVN_BEGINLABELEDIT, $TVN_BEGINLABELEDITW
                $bTreeEdit = True
;~              $hTreeEdit = _SendMessage($hTree, $TVM_GETEDITCONTROL, 0, 0)
            Case $TVN_ENDLABELEDITW, $TVN_ENDLABELEDITW
                $bTreeEdit = False
                Return 1
            Case $TVN_SELCHANGED, $TVN_SELCHANGEDW
;~              ;Local $hSel = _GUICtrlTreeView_GetSelection($hTree)
;~              Local $tNMTREEVIEW = DllStructCreate($tagNMTREEVIEW, $lParam)
;~              Local $hSel = DllStructGetData($tNMTREEVIEW, "NewhItem")
;~              Local $sTxt = "Currently selected: " & _GUICtrlTreeView_GetText($hTree, $hSel) & " (item handle " & $hSel & ")"
;~              GUICtrlSetData($label2, $sTxt)
            Case Else
        EndSwitch
        ;
    EndIf
EndFunc
Func KeyPressed($iHexKey)
    Local $aRet = DllCall('user32.dll', "int", "GetAsyncKeyState", "int", $iHexKey)
;~  If BitAND($aRet[0], 0x8000) Or BitAND($aRet[0], 1) Then Return 1
    If BitAND($aRet[0], 1) Then Return 1
    Return 0
EndFunc
Func TreeKeyboardFunc($cID)
    Local $hWnd = GUICtrlGetHandle($cID)
    If $bTreeDrag Then Return
    If $bTreeEdit Then
        If KeyPressed(0x0d) Then _SendMessage($hWnd, $TVM_ENDEDITLABELNOW, 0, 0) ;enter
        If KeyPressed(0x1b) Then _SendMessage($hWnd, $TVM_ENDEDITLABELNOW, 1, 0) ;esc
    EndIf
    Local $aRet = DllCall('user32.dll', 'hwnd', 'GetFocus')
    If $aRet[0] = $hWnd Then
        If KeyPressed(0x2d) Then _GUICtrlTreeView_Add($hWnd, _GUICtrlTreeView_GetSelection($hWnd), "New Item") ;insert
        If KeyPressed(0x2e) Then _GUICtrlTreeView_Delete($hWnd, _GUICtrlTreeView_GetSelection($hWnd)) ;delete
        If KeyPressed(0x0d) Then _SendMessage($hWnd, $TVM_EDITLABEL, 0, _GUICtrlTreeView_GetSelection($hWnd)) ;enter
    EndIf
EndFunc
Func TreeCreateDragImage($hWnd, $hItem)
    ;if treeview has imagelist, use image from it
    If _GUICtrlTreeView_GetNormalImageList($hWnd) <> 0 Then Return _GUICtrlTreeView_CreateDragImage($hWnd, $hItem)
    ;if not, create a bitmap of dragitem's text rectangle and put it into imagelist.
    Local $aItemRect = _GUICtrlTreeView_DisplayRect($hWnd, $hItem, True)
    Local $iImgW = $aItemRect[2]-$aItemRect[0]
    Local $iImgH = $aItemRect[3]-$aItemRect[1]
    Local $hTreeDC = _WinAPI_GetDC($hWnd)
    Local $hMemDC = _WinAPI_CreateCompatibleDC($hTreeDC)
    Local $hMemBmp = _WinAPI_CreateCompatibleBitmap($hTreeDC, $iImgW, $iImgH)
    Local $hMemBmpOld = _WinAPI_SelectObject($hMemDC, $hMemBmp)
    _WinAPI_BitBlt($hMemDC, 0, 0, $iImgW, $iImgH, $hTreeDC, $aItemRect[0], $aItemRect[1], $SRCCOPY)
    _WinAPI_SelectObject($hMemDC, $hMemBmpOld)
    _WinAPI_ReleaseDC($hWnd, $hTreeDC)
    _WinAPI_DeleteDC($hMemDC)
    Local $hImgList = _GUIImageList_Create($iImgW, $iImgH, 6)
    _GUIImageList_Add($hImgList, $hMemBmp)
    _WinAPI_DeleteObject($hMemBmp)
    Return $hImgList
EndFunc
; Draw drag image
; by Gary Frost (gafrost) (?)
Func DrawDragImage(ByRef $hControl, ByRef $aDrag)
    Local $tPoint, $hDC
    $hDC = _WinAPI_GetWindowDC($hControl)
    $tPoint = _WinAPI_GetMousePos(True, $hControl)
    _WinAPI_InvalidateRect($hControl)
    _GUIImageList_Draw($aDrag, 0, $hDC, DllStructGetData($tPoint, "X")-10, DllStructGetData($tPoint, "Y")-8)
    _WinAPI_ReleaseDC($hControl, $hDC)
EndFunc   ;==>DrawDragImage
Edited by Siao

"be smart, drink your wine"

Link to comment
Share on other sites

>Running AU3Check (1.54.9.0) from:E:\Programme\AutoIt3

E:\Dokumente und Einstellungen\Fanta\Lokale Einstellungen\Temp\temp-37.au3(13,108) : WARNING: $TVS_EDITLABELS: possibly used before declaration.

$cTree = GUICtrlCreateTreeView(50,50,300,200,$TVS_HASBUTTONS+$TVS_HASLINES+$TVS_LINESATROOT+$TVS_EDITLABELS+

Do I need the newest beta? <_<

Link to comment
Share on other sites

Do I need the newest beta? <_<

If you want to avoid trouble fixing stuff like above, yes, using the latest beta is strongly recommended. I used v3.2.9.5 myself.

Although if AU3Check gives you only one error which you posted, you can define that constant yourself

Global Const $TVS_EDITLABELS = 0x8

Edited by Siao

"be smart, drink your wine"

Link to comment
Share on other sites

  • 1 year later...

any idea how to do this in a list box? lol

I've found examples on how to do one or the other but not both

 "I believe that when we leave a place, part of it goes with us and part of us remains... Go anywhere, when it is quiet, and just listen.. After a while, you will hear the echoes of all our conversations, every thought and word we've exchanged.... Long after we are gone our voices will linger in these walls for as long as this place remains."

Link to comment
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
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...