# Sources PureBasicConsultez toutes les sources

Nombre d'auteurs : 41, nombre de sources : 88, dernière mise à jour : 13 août 2011

Sommaire→Gadgets→TreeGadget

- Tri manuel par Drag'n Drop pour TreeGadget
- Tri manuel par Drag'n Drop pour TreeGadget (solution multi-plateforme)
- Déplacement des éléments d'un TreeGadget

Version hors-ligne
Tri manuel par Drag'n Drop pour TreeGadget

Encore un petit code pour gérer le Drag'n drop. Cette fois, il s'agit de permettre à l'utilisateur d'organiser et de trier manuellement les éléments d'un TreeGadget par glisser/déposer.
Ca peut être utile si l'un de vos programmes nécessite une gestion de liste hiérarchique par l'utilisateur. Personnellement, je vais m'en servir pour permettre aux utilisateurs de DropUpLoad d'organiser et de gérer la liste des serveurs FTP. Ca pourrait servir à gérer une liste de raccourcis, une liste de fichiers, etc.
Voir également cette solution qui bien que moins complète a l'avantage d'être multi-plateforme.

Sélectionnez

    ; Drag'nDrop manual sort for TreeGadget
    ; By Zapman
    ;
    ; This demo code shows how to implemente a drag'n drop ability for TreeGadget
    ; in order to allow the user to sort manually the gadget content by draging
    ; it elements.
    ;
    Procedure GetFolderIconHandle()
      *sfi.SHFILEINFO = AllocateMemory(SizeOf(SHFILEINFO))
      If SHGetFileInfo_("aa.txt",#FILE_ATTRIBUTE_DIRECTORY,*sfi, SizeOf(SHFILEINFO), #SHGFI_ICON| #SHGFI_SMALLICON | #SHGFI_USEFILEATTRIBUTES)
        hFolderIcon = *sfi\hIcon
      EndIf
      FreeMemory(*sfi)
      ProcedureReturn hFolderIcon
    EndProcedure

    Procedure GetTreeItemIndexFromHandle(IHandle,TreeGadgetID)
    ;   By Timo 'fr34k' Harter and Zapman
      dItem = 0
      hItem = SendMessage_(TreeGadgetID, #TVM_GETNEXTITEM, #TVGN_ROOT, 0)
      While IHandle And hItem And hItem <> IHandle
        hItem2 = SendMessage_(TreeGadgetID, #TVM_GETNEXTITEM, #TVGN_CHILD, hItem)
        Repeat
          If hItem2 = #Null: hItem2 = SendMessage_(TreeGadgetID, #TVM_GETNEXTITEM, #TVGN_NEXT, hItem): EndIf
          If hItem2 = #Null: hItem = SendMessage_(TreeGadgetID, #TVM_GETNEXTITEM, #TVGN_PARENT, hItem): EndIf
        Until hItem2 <> #Null
        hItem = hItem2
        dItem + 1
      Wend
      ProcedureReturn dItem
    EndProcedure
    ;
    Procedure HighLightTreeItem(TreeGadgetID,hItem,HighLight)
    ;   By Timo 'fr34k' Harter and Zapman
      If HighLight : HighLight = #TVIS_DROPHILITED : EndIf ; to be sure that te right value is used
      ; We'll send a #TVM_SETITEM message. We only need to change the
      ; item state, so #TVIF_STATE is enough for the mask.
      pitem.TV_ITEM
      pitem\mask = #TVIF_STATE
      pitem\hItem = hItem

      ; 'stateMask' determines, what will be changed, and 'state' sets the actual value,
      ; so here, we set the TVIS_DROPHILITED state flag to HighLight.
      pitem\state = HighLight
      pitem\stateMask = #TVIS_DROPHILITED
      Result = SendMessage_(TreeGadgetID, #TVM_SETITEM, 0, @pitem)

      ; a redraw is neccesary here to avoid problems.
      RedrawWindow_(TreeGadgetID, 0, 0, #RDW_UPDATENOW)
      ProcedureReturn Result
    EndProcedure
    ;
    Procedure GetTreeItemIconIndex(TreeGadget,hitem)
      ; by Zapman
      tvitem.TV_ITEM\mask=#TVIF_IMAGE
      tvitem\hitem=hitem
      If SendMessage_(GadgetID(TreeGadget), #TVM_GETITEM,0,@tvitem) ; get the icon index from the item
        ProcedureReturn tvitem\iImage
      Else
        ProcedureReturn -1
      EndIf
    EndProcedure
    ;
    Procedure SetTreeItemIconIndex(TreeGadget,hitem,iconeIndex)
      ; by Zapman
      tvitem.TV_ITEM\mask=#TVIF_IMAGE|#TVIF_SELECTEDIMAGE
      tvitem\hitem=hitem
      tvitem\iImage= iconeIndex
      tvitem\iSelectedImage = iconeIndex
      result = SendMessage_(GadgetID(TreeGadget), #TVM_SETITEM,0,@tvitem) ; set the icon index from the item
      ProcedureReturn result
    EndProcedure
    ;
    Procedure InvertTreeGadgetItems(TreeGadget,p1,p2)
      t1$=GetGadgetItemText(TreeGadget,p1)
      t2$=GetGadgetItemText(TreeGadget,p2)
      SetGadgetItemText(TreeGadget,p1,t2$)
      SetGadgetItemText(TreeGadget,p2,t1$)
      iconindex1 = GetTreeItemIconIndex(TreeGadget,GadgetItemID(TreeGadget,p1)); get the icon from the first item
      iconindex2 = GetTreeItemIconIndex(TreeGadget,GadgetItemID(TreeGadget,p2)); get the icon from the second item
      SetTreeItemIconIndex(TreeGadget,GadgetItemID(TreeGadget,p1),iconindex2); set the icon for the first item
      SetTreeItemIconIndex(TreeGadget,GadgetItemID(TreeGadget,p2),iconindex1); set the icon for the second item
    EndProcedure
    ;
    ;
    Global DD_TreeGadget
    Procedure DD_TreeCallback(Window, Message, wParam, lParam)
    ;   By Timo 'fr34k' Harter for ListView Gadget
    ;   Adapted to TreeView by Zapman
      Shared OldTreeItem,TreeIsDraging,DraggedItemsList$,DragImageList
      result = #PB_ProcessPureBasicEvents

      ; The first message we need is #TVN_BEGINDRAG. This is a so called
      ; Notification message. This means, that you don't get a message called
      ; #TVN_BEGINDRAG, but you get a #WM_NOTIFY message, with further information,
      ; that tells you, that it is #TVN_BEGINDRAG

      If Message = #WM_NOTIFY
        ; The lparam paramenter contains a pointer to a NMHDR structure. There is
        ; the information about the Message
        *nmhdr.NMHDR = lParam

        ; The 'hwndfrom' member tells you, which Gadget actually sent the message
        ; This must be always checked to be sure, it is the right gadget.
        ; We allow only our own Gadgets:
        If *nmhdr\hwndfrom = GadgetID(DD_TreeGadget)

          ; The 'code' member contains the real message, in our case #TVN_BEGINDRAG
          If *nmhdr\code = #TVN_BEGINDRAG
            ; Ok, for the #TVN_BEGINDRAG notification message, lParam is a pointer to a
            ; NMTREEVIEW Structure. You might think that this can't be, as lParam allready
            ; pointed to a NMHDR structure, but this is correct, as NMTREEVIEW has a
            ; NMHDR structure inside, it only adds more members to it.

            *nmv.NMTREEVIEW = lParam

            ; The 'hItem' member contains the index of the source item, which we will need
            ; later.
            TreeItemSource = *nmv\itemNew\hItem
            OldTreeItem = TreeItemSource ; will be used to unhilite the item which was hilited

            ; By sending a #TVM_CREATEDRAGIMAGE message to the gadget, we create an ImageList
            ; that contains just one image, the drag&drop image. We will need the Imagelist WinAPI
            ; commands to work with that one later.
            HighLightTreeItem(GadgetID(DD_TreeGadget),TreeItemSource,0)
            HighLightTreeItem(GadgetID(DD_TreeGadget),GadgetItemID(DD_TreeGadget,GetGadgetState(DD_TreeGadget)),0)
            DragImageList = SendMessage_(GadgetID(DD_TreeGadget), #TVM_CREATEDRAGIMAGE, 0,TreeItemSource)
            ;
            ; If the user is draging a node,
            ; we'll modify the image by adding all the items contained by the node
            LImage = 400
            HImage = 600
            Pb_Image = CreateImage(#PB_Any,LImage,HImage)
            Font1 = LoadFont(#PB_Any, "Tahoma"  ,  8)
            StartDrawing(ImageOutput(Pb_Image))
            DrawingFont(FontID(Font1))
            Box(0, 0, LImage, HImage ,RGB(255,255,255))
            ItemIndex = GetTreeItemIndexFromHandle(TreeItemSource,GadgetID(DD_TreeGadget))
            ItemText$ = GetGadgetItemText(DD_TreeGadget,ItemIndex,0)
            DraggedItemsList$ = Str(ItemIndex)+Chr(13)+ReplaceString(ItemText$,Chr(13),"")+Chr(13)+"0"+Chr(13)
            DrawText(0,0,ItemText$,0,RGB(255,255,255))
            dep = TextWidth(ItemText$)
            posvert=0
            hcar = 14
            hItem = SendMessage_(GadgetID(DD_TreeGadget), #TVM_GETNEXTITEM, #TVGN_CHILD, TreeItemSource)
            If hItem
              level = 1
              Repeat
                posvert + hcar
                ItemIndex = GetTreeItemIndexFromHandle(hItem,GadgetID(DD_TreeGadget))
                ItemText$ = GetGadgetItemText(DD_TreeGadget,ItemIndex,0)
                DraggedItemsList$ + Str(ItemIndex)+Chr(13)+ReplaceString(ItemText$,Chr(13),"")+Chr(13)+Str(level)+Chr(13)
                DrawText(level*20,posvert,ItemText$,0,RGB(255,255,255))
                nWidth = TextWidth(ItemText$)+(level*20)
                If nWidth>dep ; calculate max text width for our draging image
                  dep = nWidth
                EndIf
                hItem2 = SendMessage_(GadgetID(DD_TreeGadget), #TVM_GETNEXTITEM, #TVGN_CHILD, hItem) ; is the next item a child ?
                If hItem2
                  level + 1
                  hItem = hItem2
                Else
                  hItem2 = SendMessage_(GadgetID(DD_TreeGadget), #TVM_GETNEXTITEM, #TVGN_NEXT, hItem) ; is it a same level item ?
                  If hItem2
                    hItem = hItem2
                  Else
                    hItem = SendMessage_(GadgetID(DD_TreeGadget), #TVM_GETNEXTITEM,#TVGN_PARENT, hItem) ; get the parent of our item
                    hItem = SendMessage_(GadgetID(DD_TreeGadget), #TVM_GETNEXTITEM, #TVGN_NEXT, hItem) ; and go to the next
                    level - 1
                  EndIf
                EndIf
              Until level = 0 Or hItem = 0
            EndIf
            DraggedItemsList$ + "Store_end" + Chr(13)

            StopDrawing()
            FreeFont(Font1)

            ImageList_SetIconSize_(DragImageList,dep+5,posvert+hcar)
            ImageList_AddMasked_(DragImageList,ImageID(Pb_Image),RGB(255,255,255))
            FreeImage(Pb_Image)

            If DragImageList
              ; This begins the drag&drop operation by displaying the image
              If ImageList_BeginDrag_(DragImageList , 0, 0, 0)

                ; this command shows or hides the drag&drop image. Or course,
                ; we want to see it now :)
                ImageList_DragShowNolock_(#True)

                ; this causes windows to send all mouse messages to our window,
                ; even if the mouse is outside of our window. This is neccesary,
                ; because we need to detect the mouseup event to abort the
                ; operation, even if the mouse is outside our window.
                SetCapture_(GetParent_(GadgetID(DD_TreeGadget)))

                ; hide the standard cursor
                ShowCursor_(#False)

                ; When processing the other events, we need to know whether something
                ; is being draged or not.
                TreeIsDraging = #True

              EndIf ; check for ImageList_BeginDrag_()

            EndIf ; check for DragImageList

          EndIf ; check for #TVN_BEGINDRAG

        EndIf ; check for right gadget

      ; The next message we need is #WM_MOUSEMOVE, to update the mouse.
      ; But only if TreeIsDraging is #TRUE.
      ElseIf Message = #WM_MOUSEMOVE And TreeIsDraging

        ; now we hide the image to avoid redrawn problems.
        ImageList_DragShowNolock_(#False)

        ; the next thing we do is hilighting the target item in the target gadget.
        GetWindowRect_(GadgetID(DD_TreeGadget),re.RECT)
        GetCursorPos_(pt.POINT)
        If PtInRect_(@re, pt\x | (pt\y<<32))

          ; What we need next is the Item, that is currently under the mouse cursor.
          ; the #TVM_HITTEST message does that test for us.

          ; here, we need coordinates relative to the top/left corner of our target
          ; Gadget, so we substract the Gadget position from our window coordinates
          ;  When #EM_MOUSEMOVE is sent, the lParam parameter contains
          ; the x coordinate in the low-word and the y coordinate in the high-word, so we
          ; just use them here:
          MouseX = lParam & $FFFF
          MouseY = lParam >> 16
          hittestinfo.TV_HITTESTINFO
          hittestinfo\pt\x = MouseX - GadgetX(DD_TreeGadget)
          hittestinfo\pt\y = MouseY - GadgetY(DD_TreeGadget)

          ; find the item, if none is under the cursor, we get -1, and the next
          ; SendMessage won't work, and nothing is hilighted.
          TargetItem = SendMessage_(GadgetID(DD_TreeGadget), #TVM_HITTEST, 0, @hittestinfo)
          If TargetItem<>-1 And TargetItem<>OldTreeItem
            If OldTreeItem
              HighLightTreeItem(GadgetID(DD_TreeGadget),OldTreeItem,0) ; Unhilighte the precedent hilighted item
            EndIf
            OldTreeItem = TargetItem
            HighLightTreeItem(GadgetID(DD_TreeGadget),OldTreeItem,1)
          EndIf
        Else ; scroll treegadget if mouse is upper or lower than it
          GetWindowRect_(GadgetID(DD_TreeGadget),re.RECT)
          GetCursorPos_(@MP.POINT)
          If MP\y < re\top
            SendMessage_(GadgetID(DD_TreeGadget), #WM_VSCROLL, #SB_LINEUP, 0);
          EndIf
          If MP\y > re\bottom
            SendMessage_(GadgetID(DD_TreeGadget), #WM_VSCROLL, #SB_LINEDOWN, 0);
          EndIf
        EndIf

        ; now we can show the drag image again:
        ImageList_DragShowNolock_(#True)

            ; this moves the drag Image.
        GetCursorPos_(@MP.Point)
        ImageList_DragMove_(MP\x, MP\y-7)

        ; that's all to do while moving the mouse. Of course, there can be more checks added,
        ; and for example, a different cursor displayed, if you don't want the source to
        ; be draged to the current target and so on, but i think this is enough for a basic
        ; example.

      ; next is the end of the drag&drop operation... when the user releases the mouse.
      ElseIf Message = #WM_LBUTTONUP And TreeIsDraging
        ; first, we release all we did, to unlock the mouse.

        ; mouse messages will be sent to other windows again
        ReleaseCapture_()

        ; and drag&drop (remove the image)
        ImageList_EndDrag_()

        ; free the image list
        ImageList_Destroy_(DragImageList)

        ; show cursor again
        ShowCursor_(#True)

        ; no draging in progress now.
        TreeIsDraging = #False

        ; next, we unhilight the last target item
        If OldTreeItem
          HighLightTreeItem(GadgetID(DD_TreeGadget),OldTreeItem,0)
        EndIf

        GetWindowRect_(GadgetID(DD_TreeGadget),re.RECT)
        GetCursorPos_(pt.POINT)
        If PtInRect_(@re, pt\x | (pt\y<<32))
          ; now, move the items as demanded by the user:
          ;
          ; examine items at old positions
          ;
          nbitems = 0
          FIndex = -1
          ct = 0
          Repeat
            ct + 1
            LValue$ = StringField(DraggedItemsList$,ct,Chr(13))
            If LValue$ <> "Store_end"
              ItemIndex = Val(LValue$)
              If FIndex = -1 : FIndex = ItemIndex: EndIf
              ct + 2
              nbitems + 1
            EndIf
          Until LValue$ = "Store_end"
          ;
          ; add items at new position
          ;
          nPosition = GetTreeItemIndexFromHandle(OldTreeItem,GadgetID(DD_TreeGadget))+1
          If nPosition>FIndex And nPosition<(FIndex+nbitems+1)
            Debug "Trying to put a node inside its own content !!!!"
          Else
            mnPosition = nPosition
            nLevel = GetGadgetItemAttribute(DD_TreeGadget,nPosition-1,#PB_Tree_SubLevel)
            iconindex = GetTreeItemIconIndex(DD_TreeGadget,GadgetItemID(DD_TreeGadget,nPosition-1))
            If iconindex And iconindex<>-1 ; get the icon from the target item
              Debug "target is a folder"   ; if there is one, we suppose that the item is a folder (a potential node)
              nLevel + 1
            EndIf
            ct = 0
            Repeat
              ct + 1
              LValue$ = StringField(DraggedItemsList$,ct,Chr(13))
              If LValue$ <> "Store_end"
                ItemIndex = Val(LValue$)
                ct + 1
                ItemText$ = StringField(DraggedItemsList$,ct,Chr(13))
                ct + 1
                level = Val(StringField(DraggedItemsList$,ct,Chr(13)))
                If FIndex>= mnPosition
                  ItemIndex + nPosition - mnPosition
                EndIf
                iconindex = GetTreeItemIconIndex(DD_TreeGadget,GadgetItemID(DD_TreeGadget,ItemIndex)); get the icon from the old item
                AddGadgetItem(DD_TreeGadget, nPosition, ItemText$,0,level+nLevel)
                SetTreeItemIconIndex(DD_TreeGadget,GadgetItemID(DD_TreeGadget,nPosition),iconindex); set the icon for the new item
                nPosition + 1
              EndIf
            Until LValue$ = "Store_end"

            If FIndex>= mnPosition ; position has to be adjusted if items to delete are after added items
              FIndex + nbitems
              nPosition = mnPosition
            Else
              nPosition = mnPosition-nbitems
            EndIf
            RemoveGadgetItem(DD_TreeGadget,FIndex)

            SetGadgetState(DD_TreeGadget,nPosition)
            SetActiveGadget(DD_TreeGadget)
          EndIf ; IsMouseOver(GadgetID(DD_TreeGadget))
        EndIf ; If Message = #WM_LBUTTONUP And TreeIsDraging

      EndIf ; check Message

      ProcedureReturn Result
    EndProcedure
    ;
    Global hFolderIcon
    Procedure Enable_DragnDrop_On_TreeGadget(Window,TreeGadget)
      DD_TreeGadget = TreeGadget
      hWndTV = GadgetID(TreeGadget)
      Style = GetWindowLong_(hWndTV, #GWL_STYLE)
      Style = Style & (~#TVS_DISABLEDRAGDROP)
      SetWindowLong_(hWndTV, #GWL_STYLE, Style) ; enable drag'n drop for the gadget
      ;
      hFolderIcon = GetFolderIconHandle() ; get a folder icon to use later in our list
      ;
      SendMessage_(hWndTV, #TVM_GETIMAGELIST,#TVSIL_NORMAL,imageList)
      If imageList = 0 ; The TreeGadget has no image list!! We need one, so we'll create one.
        AddGadgetItem(TreeGadget, -1, "ToDelete", hFolderIcon,0) ; PB will automatically create an image list if we add an item with an icon
        RemoveGadgetItem(TreeGadget, CountGadgetItems(TreeGadget)-1) ; OK, we can now delete this item
      EndIf
      ;
      SetWindowCallback(@DD_TreeCallback(),Window)
    EndProcedure

    ; Window und Gadget...
    winMain = OpenWindow(#PB_Any, 0, 0, 350, 260, "Drag'n Drop sorting with a TreeView", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)

    TreeGadget = TreeGadget(#PB_Any, 5, 5, 200, 250,#PB_Tree_AlwaysShowSelection)
    Enable_DragnDrop_On_TreeGadget(winMain,TreeGadget)

    ItemString = StringGadget(#PB_Any,220,5,120,20,"")

    TextGadget = TextGadget(#PB_Any, 220, 50, 120, 250,"You can sort this treeview manually by draging items from one position to another one.")

    PosVert = 160
    BNewFolder = ButtonGadget(#PB_Any,220,PosVert,120,20,"New Folder")
    PosVert + 25
    BNewItem = ButtonGadget(#PB_Any,220,PosVert,120,20,"New Item")
    PosVert + 25
    BDelete = ButtonGadget(#PB_Any,220,PosVert,120,20,"Delete")
    PosVert + 25
    BSort = ButtonGadget(#PB_Any,220,PosVert,120,20,"Alphabetical Sort")

    AddGadgetItem(TreeGadget, -1, "Item1"+Chr(13), 0,0)
    AddGadgetItem(TreeGadget, -1, "Folder#1", hFolderIcon,0)
      AddGadgetItem(TreeGadget, -1, "Item11",0,1)
      AddGadgetItem(TreeGadget, -1, "Item12",0,1)
      AddGadgetItem(TreeGadget, -1, "Folder#12",hFolderIcon,1)
        AddGadgetItem(TreeGadget, -1, "Item121",0,2)
        AddGadgetItem(TreeGadget, -1, "Item122",0,2)
    AddGadgetItem(TreeGadget, -1, "Folder#2", hFolderIcon,0)
      AddGadgetItem(TreeGadget, -1, "Itemz11",0,1)
      AddGadgetItem(TreeGadget, -1, "zItem1a",0,1)

    For ct = 1 To 20
      AddGadgetItem(TreeGadget, -1, "Item"+Str(ct+1),0,0)
    Next
    SetGadgetState(TreeGadget,0)
    SetGadgetText(ItemString,GetGadgetText(TreeGadget))
    SendMessage_(GadgetID(ItemString), #EM_SETSEL, 0, Len(GetGadgetText(TreeGadget)))
    SetActiveGadget(ItemString)

    Repeat
      Event = WaitWindowEvent()
      If Event = #PB_Event_Gadget
        If EventGadget() = TreeGadget
          ItemText$ = GetGadgetItemText(TreeGadget,GetGadgetState(TreeGadget))
          SetGadgetText(ItemString,ItemText$)
          SendMessage_(GadgetID(ItemString), #EM_SETSEL, 0, Len(ItemText$))
        EndIf
        If EventGadget() = ItemString And EventType() = #PB_EventType_Change
          SetGadgetItemText(TreeGadget,GetGadgetState(TreeGadget),GetGadgetText(ItemString))
        ElseIf EventGadget() = BNewFolder Or EventGadget() = BNewItem
          IIndex = GetGadgetState(TreeGadget)+1
          If EventGadget() = BNewFolder
            AddGadgetItem(TreeGadget,IIndex,"New folder",hFolderIcon)
          Else
            AddGadgetItem(TreeGadget,IIndex,"New item")
          EndIf
          SetGadgetState(TreeGadget,IIndex)
          ItemText$ = GetGadgetItemText(TreeGadget,IIndex)
          SetGadgetText(ItemString,ItemText$)
          SendMessage_(GadgetID(ItemString), #EM_SETSEL, 0, Len(ItemText$))
          SetActiveGadget(ItemString)
        ElseIf EventGadget() = BDelete
          IIndex = GetGadgetState(TreeGadget)
          RemoveGadgetItem(TreeGadget, IIndex)
          SetGadgetState(TreeGadget,IIndex)
          SetGadgetText(ItemString,ItemText$)
          SendMessage_(GadgetID(ItemString), #EM_SETSEL, 0, Len(ItemText$))
          SetActiveGadget(TreeGadget)
        ElseIf EventGadget() = BSort
          ; Windows API has a sort function for treeview (#TVM_SORTCHILDREN message)
          ; but we can't use it because the PureBasic element index is not sorted with the elements.
          ; So, we recreate a complete sort function for PB treegadget.
          lastitem = CountGadgetItems(TreeGadget)-1
          maxlevel = 0
          For clevel = 0 To maxlevel
            For i=0 To lastitem-1
              nlevel = GetGadgetItemAttribute(TreeGadget,i,#PB_Tree_SubLevel)
              If nlevel>maxlevel : maxlevel = nlevel : EndIf
              If nlevel = clevel
                min=i
                For j=i+1 To lastitem
                  If GetGadgetItemText(TreeGadget,j)<GetGadgetItemText(TreeGadget,min) And GetGadgetItemAttribute(TreeGadget,j,#PB_Tree_SubLevel)=clevel
                    min=j
                  EndIf
                  If GetGadgetItemAttribute(TreeGadget,j,#PB_Tree_SubLevel)<nlevel
                    j = lastitem
                  EndIf
                Next
                If min<>i
                  For b = 1 To 2
                    storeitems$ = ""
                    If b = 1
                      posd = i
                    Else
                      posd = min
                    EndIf
                    ; Store the node content
                    ct = 1
                    While GetGadgetItemAttribute(TreeGadget,posd+ct,#PB_Tree_SubLevel)>clevel
                      storeitems$ + GetGadgetItemText(TreeGadget,posd+ct)+Chr(13)+Str(GetGadgetItemAttribute(TreeGadget,posd+ct,#PB_Tree_SubLevel))+Chr(13)+Str(GetTreeItemIconIndex(TreeGadget,GadgetItemID(TreeGadget,posd+ct)))+Chr(13)
                      ct + 1
                      If b = 1 And min>i
                        min - 1
                      EndIf
                      If b = 2 And i>min
                        i - 1
                      EndIf
                    Wend
                    If b = 1
                      storeitems_i$ = storeitems$
                    Else
                      storeitems_min$ = storeitems$
                    EndIf
                    ; Delete the node content
                    While GetGadgetItemAttribute(TreeGadget,posd+1,#PB_Tree_SubLevel)>clevel
                      RemoveGadgetItem(TreeGadget,posd+1)
                    Wend
                  Next
                  ; recreate the node content at the right place
                  For b = 1 To 2
                    If b = 1
                      posi = min
                      storeitems$ = storeitems_i$
                    Else
                      posi = i
                      storeitems$ = storeitems_min$
                    EndIf
                    ct = 0
                    Repeat
                      ct + 1
                      itemtext$ = StringField(storeitems$,ct,Chr(13))
                      If itemtext$
                        ct + 1
                        level = Val(StringField(storeitems$,ct,Chr(13)))
                        ct + 1
                        iconindex = Val(StringField(storeitems$,ct,Chr(13)))
                        posi + 1
                        AddGadgetItem(TreeGadget,posi,itemtext$,0,level)
                        SetTreeItemIconIndex(TreeGadget,GadgetItemID(TreeGadget,posi),iconindex)
                        If b = 1 And i>min
                          i + 1
                        EndIf
                        If b = 2 And min>i
                          min + 1
                        EndIf
                      EndIf
                    Until itemtext$ = ""
                  Next
                  InvertTreeGadgetItems(TreeGadget,i,min)
                EndIf
              EndIf
            Next
          Next
          SetGadgetState(TreeGadget,0)
          SetGadgetText(ItemString,GetGadgetText(TreeGadget))
          SendMessage_(GadgetID(ItemString), #EM_SETSEL, 0, Len(GetGadgetText(TreeGadget)))
          SetActiveGadget(ItemString)
        EndIf
      EndIf
    Until Event = #PB_Event_CloseWindow
    End

Créé le 28 août 2010 par Zapman
Tri manuel par Drag'n Drop pour TreeGadget (solution multi-plateforme)

Cette solution bien que moins complète que celle-ci, a l'avantage d'être multi-plateforme (Windows, Linux, Mac OS).

Sélectionnez

    ; ------------------------------------------------------------------
    ;
    ;   Example for Drag & Drop inside a TreeGadget to reorder items.
    ;
    ;   Requires 4.10 beta or newer to run
    ;
    ; ------------------------------------------------------------------

    #Tree = 0
    #Window = 0

    ; If you want to do multiple drag&drop in different Gadgets of your program,
    ; you can use different values here so the events do not collide.
    ; (ie so the user cannot drag to the wrong gadget)
    #PrivateType = 0

    If OpenWindow(#Window, 0, 0, 300, 500, "TreeGadget Drag & Drop", #PB_Window_ScreenCentered|#PB_Window_SystemMenu)
      CreateGadgetList(WindowID(#Window))
      TreeGadget(#Tree, 10, 10, 280, 480)

      ; Add some items. We will be able to move items into the
      ; "Directory" ones.
      ;
      For i = 0 To 20
        If i % 5 = 0
          AddGadgetItem(#Tree, -1, "Directory" + Str(i), 0, 0)
        Else
          AddGadgetItem(#Tree, -1, "Item" + Str(i), 0, 0)
        EndIf
      Next i

      ; this enables dropping our private type with a move operation
      EnableGadgetDrop(#Tree, #PB_Drop_Private, #PB_Drag_Move, #PrivateType)

      Repeat
        Event = WaitWindowEvent()

        If Event = #PB_Event_Gadget
          ;
          ; The DragStart event tells us that the user clicked on an item and
          ; wants to start draging it. We save this item for later use and
          ; start our private drag
          ;
          If EventGadget() = #Tree And EventType() = #PB_EventType_DragStart
            SourceItem = GetGadgetState(#Tree)
            DragPrivate(#PrivateType, #PB_Drag_Move)
          EndIf

        ElseIf Event = #PB_Event_GadgetDrop
          ;
          ; Here we get a drop event. Make sure it is on the right gadget and of right type,
          ; especially if you have multiple Drag & Drop stuff in your program.
          ;
          If EventGadget() = #Tree And EventDropType() = #PB_Drop_Private And EventDropPrivate() = #PrivateType
            TargetItem = GetGadgetState(#Tree)

            ; nothing to do if source and target are equal
            ;
            If SourceItem <> TargetItem

              ; Find out to which index and sublevel to move the item
              ;
              If TargetItem = -1
                ; if dropped on the empty area, append at the end
                TargetItem  = CountGadgetItems(#Tree)
                TargetLevel = 0

              ElseIf Left(GetGadgetItemText(#Tree, TargetItem), 4) = "Item"
                ; if dropped on an "Item", move right after this item
                TargetLevel = GetGadgetItemAttribute(#Tree, TargetItem, #PB_Tree_SubLevel)
                TargetItem  + 1

              Else
                ; if dropped on a "Directory", move into the directory and to the end of it
                ; all this can be easily done by examining the sublevel
                TargetLevel = GetGadgetItemAttribute(#Tree, TargetItem, #PB_Tree_SubLevel) + 1
                TargetItem  + 1
                While GetGadgetItemAttribute(#Tree, TargetItem, #PB_Tree_SubLevel) >= TargetLevel
                  TargetItem + 1
                Wend

              EndIf

              ; Find out how many children our source item has, as we want to
              ; move them all. If you do not allow moving of directory nodes, it gets
              ; much simpler as there is only one delete + add then.
              ;
              ; childnodes are all directly following ones with a higher level
              ;
              SourceLevel = GetGadgetItemAttribute(#Tree, SourceItem, #PB_Tree_SubLevel)
              ChildCount  = 0
              For i = SourceItem+1 To CountGadgetItems(#Tree)-1
                If GetGadgetItemAttribute(#Tree, i, #PB_Tree_SubLevel) > SourceLevel
                  ChildCount + 1
                Else
                  Break
                EndIf
              Next i

              ; Note: because by adding new items, the index of our old ones changes,
              ;   we need to make a distinction here wether we move before or after our old item.
              ;   Note also that we cannot move an item into one of its childs, which we
              ;   prevent by this check as well.
              ;
              ; We copy first the source item and all children to the new location and then
              ; delete the source item.
              ;
              If TargetItem > SourceItem + ChildCount + 1
                ;
                ; The target index is higher than the source one, so the source items are not
                ; affected by adding the new items in this case...
                ;
                For i = 0 To ChildCount
                  ; copy everything here (also colors and GetGadgetItemData() etc if you use that)
                  Text$ = GetGadgetItemText(#Tree, SourceItem+i)
                  Level = GetGadgetItemAttribute(#Tree, SourceItem+i, #PB_Tree_SubLevel) - SourceLevel + TargetLevel
                  AddGadgetItem(#Tree, TargetItem+i, Text$, 0, Level)
                Next i

                ; We apply the state of each item AFTER all items are copied.
                ; This must be in a separate loop, as else the "expanded" state of the items is
                ; not preserved, as the childs were not added yet in the above loop.
                For i = 0 To ChildCount
                  SetGadgetItemState(#Tree, TargetItem+i, GetGadgetItemState(#Tree, SourceItem+i))
                Next i

                ; remove the source item. This automatically removes all children as well.
                RemoveGadgetItem(#Tree, SourceItem)

                ; select the target. Note that the index is now 'ChildCount+1' less
                ; because of the remove of the source which was before the target
                SetGadgetState(#Tree, TargetItem-ChildCount-1)

              ElseIf TargetItem <= SourceItem
                ;
                ; Second case: Target is lower than source. This means that each time
                ; we add a target item, the source items index increases by 1 as well,
                ; this is why we read the source items with the "SourceItem+i*2"
                ;
                For i = 0 To ChildCount
                  Text$ = GetGadgetItemText(#Tree, SourceItem+i*2)
                  Level = GetGadgetItemAttribute(#Tree, SourceItem+i*2, #PB_Tree_SubLevel) - SourceLevel + TargetLevel
                  AddGadgetItem(#Tree, TargetItem+i, Text$, 0, Level)
                Next i

                ; Loop for the states. Note that here the index of the sourceitems is
                ; 'ChildCount+1' higher than before because of the added targets
                ;
                For i = 0 To ChildCount
                  SetGadgetItemState(#Tree, TargetItem+i, GetGadgetItemState(#Tree, SourceItem+ChildCount+1+i))
                Next i

                ; remove source and select target. Here the target index is not affected by the remove as it is lower
                RemoveGadgetItem(#Tree, SourceItem+ChildCount+1)
                SetGadgetState(#Tree, TargetItem)

              EndIf

            EndIf
          EndIf

        EndIf

      Until Event = #PB_Event_CloseWindow
    EndIf

    End

Créé le 28 août 2010 par Freak
Déplacement des éléments d'un TreeGadget

Un petit code qui permet de déplacer des éléments dans un TreeGadget.
4 boutons pour :

- Déplacer vers le haut
- Déplacer vers le bas
- Augmenter le niveau
- Diminuer le niveau

Déplacement des éléments par glisser déposer :

- Diminuer le niveau en déplaçant l'élément vers la gauche
- Augmenter le niveau en déplaçant l'élément vers la droite
- Déplacer l'élément vers le haut ou le bas

Quand on déplace ou change le niveau d'un élément, tous les enfants de l'élément sont également déplacer.
Le TreeGadget doit être rempli à partir d'une Liste.
Le code est portable, il suffit de supprimer les 2 APIs lockWindowUpdate_() qui ne servent qu'à éviter le clignotement du TreeGadget lors du remplissage avec les éléments.

Sélectionnez

    ; Auteur : Le Soldat Inconnu
    ; Version de PB : 4.50
    ;
    ; Explication du programme :
    ; Arbre modifiable

    Structure ArbreInfo
      Nom.s
      Niveau.l
      Pliage.l
    EndStructure
    Global NewList Arbre.ArbreInfo()

    #Arbre = 0
    #Fenetre = 0
    #Arbre_DragDrop_Deplacer = 0
    Global DragDrop_Start, DragDrop_Start_X

    Procedure Arbre_Pliage()
      ForEach Arbre()
        If GetGadgetItemState(#Arbre, ListIndex(Arbre())) & #PB_Tree_Expanded
          Arbre()\Pliage = 1
        Else
          Arbre()\Pliage = 0
        EndIf
      Next
    EndProcedure
    Procedure Arbre_Niveau_Correction()
      Niveau = 0
      ForEach Arbre()
        If Arbre()\Niveau > Niveau + 1
          Arbre()\Niveau = Niveau + 1
        EndIf
        If Arbre()\Niveau < 0
          Arbre()\Niveau = 0
        EndIf
        Niveau = Arbre()\Niveau
      Next
    EndProcedure
    Procedure Arbre_Remplir(Position = -1)
      LockWindowUpdate_(WindowID(0))
      ClearGadgetItems(#Arbre)
      ForEach Arbre()
        AddGadgetItem(#Arbre, -1, Arbre()\Nom, 0, Arbre()\Niveau)
        If Pliage
          SetGadgetItemState(#Arbre, ListIndex(Arbre()) - 1, #PB_Tree_Expanded)
        EndIf
        Pliage = Arbre()\Pliage
      Next
      If Position >= 0
        SetGadgetState(#Arbre, Position)
      EndIf
      LockWindowUpdate_(0)
    EndProcedure
    Procedure Arbre_Deplacer(Position, Mouvement)
      Protected PositionFinale, *Deplacer1.ArbreInfo, *Deplacer2.ArbreInfo
      Arbre_Pliage()

      If Position >= 0

        ; Vérification
        If Position + Mouvement < 0
          Mouvement = -Position
        EndIf
        If Position + Mouvement >= ListSize(Arbre())
          Mouvement = ListSize(Arbre()) - 1 - Position
        EndIf

        ; Evolution du niveau entre le départ et l'arrivée
        SelectElement(Arbre(), Position)
        Niveau = Arbre()\Niveau
        SelectElement(Arbre(), Position + Mouvement)
        Evolution = Arbre()\Niveau - Niveau
        If NextElement(Arbre())
          If Arbre()\Niveau > Niveau + Evolution
            Evolution + 1
          EndIf
        EndIf

        ; Position finale
        PositionFinale = Position + Mouvement

        ; Nombre d'élément à déplacer (Regarde le nombre d'enfants à déplacer)
        SelectElement(Arbre(), Position)
        Suivant = 0
        While NextElement(Arbre())
          If Arbre()\Niveau <= Niveau
            Break
          EndIf
          Suivant + 1
        Wend
        If Mouvement > 0 And Position + Suivant > PositionFinale
          Suivant = 0 ; Si le déplacement se fait dans un élément enfant, on ne déplace pas les enfants
        EndIf

        ; Déplacement
        Repeat

          SelectElement(Arbre(), Position)
          If Mouvement > 0
            For i = 1 To Mouvement
              *Deplacer1 = @Arbre()
              NextElement(Arbre())
              *Deplacer2 = @Arbre()
              SwapElements(Arbre(), *Deplacer1, *Deplacer2)
              ChangeCurrentElement(Arbre(), *Deplacer1)
            Next

          ElseIf Mouvement < 0
            For i = 1 To -Mouvement
              *Deplacer1 = @Arbre()
              PreviousElement(Arbre())
              *Deplacer2 = @Arbre()
              SwapElements(Arbre(), *Deplacer1, *Deplacer2)
              ChangeCurrentElement(Arbre(), *Deplacer1)
            Next

            Position + 1

          EndIf

          Arbre()\Niveau + Evolution

          Suivant - 1

        Until Suivant < 0

        Arbre_Niveau_Correction()
        Arbre_Remplir(PositionFinale)

      EndIf
    EndProcedure
    Procedure Arbre_Niveau(Position, Evolution)
      Arbre_Pliage()

      If Position >= 0
        SelectElement(Arbre(), Position)

        Niveau = Arbre()\Niveau

        ; Vérification
        If Niveau + Evolution < 0
          Evolution = -Niveau
        EndIf
        If Evolution > 0
          If PreviousElement(Arbre())
            If Niveau + Evolution > Arbre()\Niveau + 1
              Evolution = Arbre()\Niveau + 1 - Niveau
            EndIf
            NextElement(Arbre())
          EndIf
        EndIf

        ; Correction du pliage de l'arbre
        If Evolution > 0
          If PreviousElement(Arbre())
            Arbre()\Pliage = 1
            NextElement(Arbre())
          EndIf
        EndIf
        If Evolution < 0
          If NextElement(Arbre())
            If Arbre()\Niveau = Niveau
              PreviousElement(Arbre())
              Arbre()\Pliage = 1
            Else
              PreviousElement(Arbre())
            EndIf
          EndIf
        EndIf

        ; Change le niveau
        Arbre()\Niveau + Evolution
        While NextElement(Arbre())
          If Arbre()\Niveau <= Niveau
            Break
          EndIf
          Arbre()\Niveau + Evolution
        Wend

        Arbre_Niveau_Correction()
        Arbre_Remplir(Position)

      EndIf
    EndProcedure
    Procedure Arbre_GlisserDeposer()
      Protected DragDrop_X, DragDrop_End
      DragDrop_End = GetGadgetState(#Arbre)
      If DragDrop_End = -1
        DragDrop_End = CountGadgetItems(#Arbre) - 1
      EndIf
      DragDrop_X = WindowMouseX(#Fenetre) - DragDrop_Start_X

      If DragDrop_End = DragDrop_Start
        ; On change le niveau de l'élément
        If DragDrop_X > 8
          Arbre_Niveau(DragDrop_Start, 1)
        ElseIf DragDrop_X < -8
          Arbre_Niveau(DragDrop_Start, -1)
        EndIf
      Else
        ; On déplace l'élément
        Arbre_Deplacer(DragDrop_Start, DragDrop_End - DragDrop_Start)
      EndIf

    EndProcedure

    ; Création de la fenêtre et de la GadgetList
    If OpenWindow(#Fenetre, 0, 0, 500, 500, "Arbre", #PB_Window_SystemMenu | #PB_Window_ScreenCentered | #PB_Window_MinimizeGadget) = 0
      End
    EndIf

    TreeGadget(#Arbre, 0, 0, 300, 500, #PB_Tree_AlwaysShowSelection)
    EnableGadgetDrop(#Arbre, #PB_Drop_Private, #PB_Drag_Move, #Arbre_DragDrop_Deplacer)

    ButtonGadget(1, 300, 0, 200, 30, "Monter")
    ButtonGadget(2, 300, 30, 200, 30, "Descendre")
    ButtonGadget(3, 300, 60, 200, 30, "Niveau +")
    ButtonGadget(4, 300, 90, 200, 30, "Niveau -")

    ; Remplissage de l'arbre
    For i = 1 To 20
      AddElement(Arbre())
      Arbre()\Nom = "Elément " + Str(i)
    Next

    Arbre_Remplir()

    Repeat
      Event = WaitWindowEvent()

      Select Event
        Case #PB_Event_Gadget
          Position = GetGadgetState(#Arbre)
          Select EventGadget() ; Gadgets

            Case #Arbre
              Select EventType()
                Case #PB_EventType_DragStart ; Glisser déposer
                  DragDrop_Start = Position
                  DragDrop_Start_X = WindowMouseX(#Fenetre)
                  DragPrivate(#Arbre_DragDrop_Deplacer, #PB_Drag_Move)
              EndSelect

            Case 1
              Arbre_Deplacer(Position, -1)
            Case 2
              Arbre_Deplacer(Position, 1)
            Case 3
              Arbre_Niveau(Position, 1)
            Case 4
              Arbre_Niveau(Position, -1)
          EndSelect

        Case #PB_Event_GadgetDrop
          ; Opération de glisser déposer
          Select EventGadget()
            Case #Arbre
              Position = GetGadgetState(#Arbre)
              Select EventDropType()
                Case #PB_Drop_Private
                  Select EventDropPrivate()
                    Case #Arbre_DragDrop_Deplacer
                      Arbre_GlisserDeposer()
                  EndSelect
              EndSelect
          EndSelect

      EndSelect

    Until Event = #PB_Event_CloseWindow

Créé le 13 juin 2011 par Le Soldat Inconnu
Version hors-ligne

Les sources présentés sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre cette page de présentation de ces sources constitue une œuvre intellectuelle protégée par les droits d'auteurs. Copyright ©2008 Developpez LLC. Tous droits réservés Developpez LLC. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents et images sans l'autorisation expresse de Developpez LLC. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.