Sources PureBasicConsultez toutes les sources

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

 
OuvrirSommaireGadgetsTreeGadget

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

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

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
  

Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2008 Developpez 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.