Advanced: Jetzt: TreeView mit Nodes statt Ranking/Indizien

Hier könnt Ihr gute, von Euch geschriebene Codes posten. Sie müssen auf jeden Fall funktionieren und sollten möglichst effizient, elegant und beispielhaft oder einfach nur cool sein.
ShadowTurtle
Beiträge: 114
Registriert: 11.09.2004 07:58
Wohnort: Mannheim
Kontaktdaten:

Advanced: Jetzt: TreeView mit Nodes statt Ranking/Indizien

Beitrag von ShadowTurtle »

Hallo Ihr da draußen!

Jetzt gibt es von mir eine etwas leichtere Kost. Die meisten Librarys zum TreeView-Gadget bieten zwar nette Erweiterungen, sind allerdings auch nicht auf Kompatibilität mit den Purebasic-Item-Funktionen ausgelegt.

Wenn mittels AdvTree_Create ein TreeView Gadget erstellt wird, dann wird zunächst einmal ein Original-PureBasic-TreeView-Gadget erstellt. So wird auch die Kompatibilität der Events des Gadgets sichergestellt.

AdvTree_Create liefert allerdings nicht die Identifikation des PureBasic-Gadgets zurück, sondern dessen hWnd-ID. Denn so kann man diese Library ganz nach seinen Wünschen erweitern: zum Beispiel mit einen Effekt aus einen VisualBasic-Code schnipsel, welches natürlich auf die WinAPI zurückgreift.

Jetzt stellen sich sicherlich einige wieder die Frage: "Warum hat das aber bisher noch nie jemand so Realisiert?". Wobei diese Frage nur Gegenfragen aufwirft: "Wie willst Du an die PureBasic-ID des Gadgets kommen um z.B. das normale AddGadgetItem anwenden zu können?" oder auch "Wie willst du den Memory-Leak beseitigen, wenn Du die IDs mit einer Linked-List speichern würdest?"

Die Antworten würden wie folgt lauten:
Wie willst Du an die PureBasic-ID des Gadgets kommen um z.B. das normale AddGadgetItem anwenden zu können?
Ich speichere die ID mit dem hWnd des Gadgets in einer Linked-List und biete die Funktion AdvTree_GetGadget an. Wer hat diese Antwort erahnt? :)

Wie willst du den Memory-Leak beseitigen, wenn Du die IDs mit einer Linked-List speichern würdest?
Der Memory-Leak, welches entsteht wenn das Programm abrupt beendet wird, ist nicht Kritisch anzusehen, in Anbetracht der Vorteile die man hat. Zumal der größte Speicherplatz mittlerweile 2 Gigabyte misst.

Ich schätze da macht es nicht viel aus wenn nach dem Beenden mal 8 Bytes von solch einem Gadget noch Reserviert bleiben.

Was anderes wäre es, wenn jetzt auf einmal über 50.000 TreeView-Gadgets erstellt werden würden. Aber mal ernsthaft, selbst Windows schafft nur 2550 (255 * 10) Gadgets gleichzeitig auf dem Bildschirm darzustellen.

Code: Alles auswählen

; AdvancedTreeView_Sample.pb V1.0
; by ShadowTurtle @ Sonntag, 08. Juli 2007
; Wenn dieses Beispiel gestartet wurde, dann wird bei einen
; Auswahl eines Items die entsprechenden Untereinträge im
; ersten Item (oben im Gadget/Fenster) dargestellt.
IncludeFile("AdvancedTreeView.pb")

#TreeView = 1

If OpenWindow(0, 100, 100, 500, 500, "PureBasic Window")
  If CreateGadgetList(WindowID(0))
    MyTree = AdvTree_Create(#TreeView, 5, 5, 490, 490)
    TextInfo = AdvTree_AddItem( MyTree, "Click on item", 0)

    WummB = AdvTree_AddItem( MyTree, "My item " + Str(I), 0)
    MyItemA = AdvTree_AddItem( MyTree, "My item A", 0, WummB)
    MyItemC = AdvTree_AddItem( MyTree, "My item C", 0, MyItemA )
    MyItemB = AdvTree_AddItem( MyTree, "My item B", 0, MyItemA )
    MyItemD = AdvTree_AddItem( MyTree, "My item D", 0, MyItemB )

    For I = 1 To 4
      Wumm = AdvTree_AddItem( MyTree, "My item " + Str(I), 0)
      MyItemA = AdvTree_AddItem( MyTree, "My item A", 0, Wumm)
      MyItemC = AdvTree_AddItem( MyTree, "My item C", 0, MyItemA )
      MyItemB = AdvTree_AddItem( MyTree, "My item B", 0, MyItemA )
      MyItemD = AdvTree_AddItem( MyTree, "My item D", 0, MyItemB )
    Next
  EndIf  
  AdvTree_SortNode( MyTree, 0, #True )

  Repeat
    Event = WaitWindowEvent()
    WindowID = EventWindow()
    GadgetID = EventGadget()
    EventType = EventType()
    
    If Event = #PB_Event_Gadget
      If GadgetID = #TreeView
        SelectedItem = AdvTree_GetSelectedItem(MyTree)
        ItemText.s = AdvTree_GetItemText( MyTree, SelectedItem )
        
        SubItems_PrintList.s = ItemText.s + " child's:"
        WorkItem.l = AdvTree_GetItems( MyTree, SelectedItem )
        Repeat
          SubItems_PrintList.s = SubItems_PrintList.s + " " + AdvTree_GetItemText( MyTree, WorkItem.l )

          WorkItem.l = AdvTree_GetNextItem( MyTree, WorkItem.l )
        Until (WorkItem.l = #Null)
        
        AdvTree_SetItemText( MyTree, TextInfo, SubItems_PrintList.s)
      EndIf
    EndIf
  Until Event = #PB_Event_CloseWindow
EndIf

Code: Alles auswählen

; AdvancedTreeView.pb V1.0
; by ShadowTurtle @ Sonntag, 08. Juli 2007
; Die meisten Librarys zum TreeView-Gadget bieten zwar nette Erweiterungen,
; sind allerdings auch nicht auf Kompatibilität mit den Purebasic-Item-
; Funktionen ausgelegt.
; 
; Wenn mittels AdvTree_Create ein TreeView Gadget erstellt wird,
; dann wird zunächst einmal ein Original-PureBasic-TreeView-Gadget
; erstellt. So wird auch die Kompatibilität der Events des Gadgets
; sichergestellt.
; 
; AdvTree_Create liefert allerdings nicht die Identifikation des
; PureBasic-Gadgets zurück, sondern dessen hWnd-ID. Denn so kann man
; diese Library ganz nach seinen Wünschen erweitern: zum Beispiel mit
; einen Effekt aus einen VisualBasic-Code schnipsel, welches natürlich auf
; die WinAPI zurückgreift.
; 
; Jetzt stellen sich sicherlich einige wieder die Frage: "Warum hat das
; aber bisher noch nie jemand so Realisiert?". Wobei diese Frage nur
; Gegenfragen aufwirft: "Wie willst Du an die PureBasic-ID des Gadgets
; kommen um z.B. das normale AddGadgetItem anwenden zu können?" oder auch
; "Wie willst du den Memory-Leak beseitigen, wenn Du die IDs mit einer
; Linked-List speichern würdest?"
; 
; Die Antworten würden wie folgt lauten:
; "Wie willst Du an die PureBasic-ID des Gadgets kommen um z.B. das
; normale AddGadgetItem anwenden zu können?"
; Ich speichere die ID mit dem hWnd des Gadgets in einer Linked-List und
; biete die Funktion AdvTree_GetGadget an.
; 
; "Wie willst du den Memory-Leak beseitigen, wenn Du die IDs mit einer
; Linked-List speichern würdest?"
; Der Memory-Leak, welches entsteht wenn das Programm abrupt beendet
; wird, ist nicht Kritisch anzusehen, in Anbetracht der Vorteile die man
; hat. Zumal der größte Speicherplatz mittlerweile 2 Gigabyte misst.
; 
; Ich schätze da macht es nicht viel aus wenn nach dem Beenden mal 8 Bytes
; von solch einem Gadget noch Reserviert bleiben.
; 
; Was anderes wäre es, wenn jetzt auf einmal über 50.000 TreeView-Gadgets
; erstellt werden würden. Aber mal ernsthaft, selbst Windows schafft nur
; 2550 (255 * 10) Gadgets gleichzeitig auf dem Bildschirm darzustellen.

Structure AdvTree_TVITEM
  mask.l
  hItem.l
  state.l
  stateMask.l
  pszText.l
  cchTextMax.l
  iImage.l
  iSelectedImage.l
  cChildren.l
  lParam.l
EndStructure

Structure AdvTree_TVINSERTSTRUCT
  hParent.l
  hInsertAfter.l
  item.AdvTree_TVITEM
EndStructure

Structure AdvTreeItem_Struct
  item.l
  itemData.l
EndStructure

Structure AdvTreeGadget
  hwnd.l
  PureGadget.l
  *NextGadget.AdvTreeGadget
EndStructure
Global *AdvTreeLastGadget.AdvTreeGadget
*AdvTreeLastGadget = 0

Procedure.l AdvTree_GetGadget(hwnd.l)
  GetBackPureGadget.l = -1
  *AdvSTG = *AdvTreeLastGadget
  While( *AdvSTG )
    *I_AdvSTG.AdvTreeGadget = *AdvSTG
    If hwnd.l = *I_AdvSTG\hwnd
      GetBackPureGadget.l = *I_AdvSTG\PureGadget
      ;Break
    EndIf
    
    *AdvSTG = *I_AdvSTG\NextGadget
  Wend
  
  ProcedureReturn( GetBackPureGadget.l )
EndProcedure

Procedure.l AdvTree_Create( Gadget.l, x.l, y.l, width.l, height.l, flags.l = #PB_Explorer_AlwaysShowSelection )
  If Gadget.l = #PB_Any
    Gadget.l = TreeGadget( #PB_Any, x.l, y.l, width.l, height.l, flags.l)
  Else
    TreeGadget( Gadget.l, x.l, y.l, width.l, height.l, flags.l)
  EndIf
  
  *AdvTG.AdvTreeGadget = AllocateMemory(SizeOf(AdvTreeGadget))
  *AdvTG\hwnd = GadgetID( Gadget )
  *AdvTG\PureGadget = Gadget.l
  *AdvTG\NextGadget = *AdvTreeLastGadget
  *AdvTreeLastGadget = *AdvTG
  
  AddGadgetItem( Gadget.l, 0, "temp")
  RemoveGadgetItem( Gadget.l, 0)
  SetFocus_( Gadget )
  ProcedureReturn GadgetID( Gadget )
EndProcedure

Procedure AdvTree_SetFocus( Gadget )
  SetFocus_( Gadget )
EndProcedure

Procedure AdvTree_Lock( Gadget )
  SendMessage_(Gadget, #WM_SETREDRAW, #False, 0)
EndProcedure

Procedure AdvTree_Unlock( Gadget )
  SendMessage_(Gadget, #WM_SETREDRAW, #True, 0)
EndProcedure

Procedure.l AdvTree_AddItem( Gadget, text.s, hImg.l, parent.l = 0 )
  If ( parent.l = 0 )
    parent.l = #TVGN_ROOT
  EndIf

  lpis.AdvTree_TVINSERTSTRUCT

  lpis\hParent = parent
  lpis\hInsertAfter = #TVI_LAST ;#TVI_SORT

  lpis\item\iImage = 0
  lpis\item\iSelectedImage = 0
  lpis\item\mask = #TVIF_TEXT
  lpis\item\pszText = @text

  NewItem.l = SendMessage_(Gadget, #TVM_INSERTITEM, 0, @lpis)

  ProcedureReturn NewItem
EndProcedure

Procedure.s AdvTree_GetItemText( Gadget, item.l )
  text.s = Space(999)

  pitem.AdvTree_TVITEM
  pitem\mask = #TVIF_TEXT
  pitem\hItem = item
  pitem\pszText = @text
  pitem\cchTextMax = 999

  SendMessage_(Gadget, #TVM_GETITEM, 0, @pitem)
  ProcedureReturn Trim(PeekS(pitem\pszText))
EndProcedure

Procedure AdvTree_SetItemText( GadGet, Item.l, text.s )
  pitem.AdvTree_TVITEM
  pitem\mask = #TVIF_TEXT
  pitem\hItem = Item
  pitem\pszText = @text
  pitem\cchTextMax = Len(text)
  SendMessage_(GadGet, #TVM_SETITEM, 0, @pitem)
EndProcedure

Procedure AdvTree_GetParentItem( GadGet, Item.l )
  Result = SendMessage_( GadGet, #TVM_GETNEXTITEM, #TVGN_PARENT, Item)
  If ( Result = #TVGN_ROOT )
    ProcedureReturn 0
  Else
    ProcedureReturn Result
  EndIf
EndProcedure

Procedure AdvTree_DeleteItem( GadGet, Item.l )
  SendMessage_(GadGet, #TVM_DELETEITEM, 0, Item)
EndProcedure


Procedure AdvTree_SelectItem( GadGet, Item.l )
  ProcedureReturn SendMessage_(GadGet, #TVM_SELECTITEM, #TVGN_CARET, Item)
EndProcedure

Procedure.l AdvTree_GetSelectedItem( GadGet )
  ProcedureReturn SendMessage_(GadGet, #TVM_GETNEXTITEM, #TVGN_CARET, #Null)
EndProcedure


Procedure AdvTree_ExpandNode( GadGet, Item.l )
  SendMessage_( GadGet, #TVM_EXPAND, #TVE_EXPAND, Item)
EndProcedure

Procedure AdvTree_ToggleNode( GadGet, Item.l )
  SendMessage_( GadGet, #TVM_EXPAND, #TVE_TOGGLE, Item)
EndProcedure

Procedure AdvTree_CollapseNode( GadGet, Item.l )
  SendMessage_( GadGet, #TVM_EXPAND, #TVE_COLLAPSE, Item)
EndProcedure


Procedure.l AdvTree_GetItems( Gadget, item.l = #TVGN_ROOT )
  If ( item.l = #TVGN_ROOT )
    ProcedureReturn SendMessage_( Gadget, #TVM_GETNEXTITEM, #TVGN_ROOT, 0)
  Else
    ProcedureReturn SendMessage_( Gadget, #TVM_GETNEXTITEM, #TVGN_CHILD, item)
  EndIf
EndProcedure

Procedure.l AdvTree_GetNextItem( Gadget, item.l )
  ProcedureReturn SendMessage_( Gadget, #TVM_GETNEXTITEM, #TVGN_NEXT, item)
EndProcedure


Procedure AdvTree_SortNode( Gadget, item.l, subnodes.l = #False )
  SendMessage_(Gadget, #TVM_SORTCHILDREN, subnodes.l, item)
EndProcedure

Procedure AdvTree_Clear( Gadget )
  SendMessage_(Gadget, #TVM_DELETEITEM, 0, #TVGN_ROOT)
EndProcedure

Procedure AdvTree_Destroy( Gadget )
  SendMessage_(Gadget, #TVM_DELETEITEM, 0, #TVGN_ROOT)
  
  GetBackPureGadget.l = -1
  *AdvLastSTG = 0
  *AdvSTG = *AdvTreeLastGadget
  While( *AdvSTG )
    *I_AdvSTG.AdvTreeGadget = *AdvSTG
    If Gadget.l = *I_AdvSTG\hwnd
      *I_AdvLastSTG.AdvTreeGadget = *AdvLastSTG
      *I_AdvLastSTG\NextGadget = *I_AdvSTG\NextGadget
      FreeMemory( *I_AdvSTG )
      Break
    EndIf
    
    *AdvLastSTG = *I_AdvSTG
    *AdvSTG = *I_AdvSTG\NextGadget
  Wend
EndProcedure


Procedure.l AdvTree_AddItemB( Gadget, text.s, hImg.l, parent.l = 0)
  If ( parent.l = 0 )
    ItemWork.l = SendMessage_( Gadget, #TVM_GETNEXTITEM, #TVGN_ROOT, 0)
    openflag = 0
  Else
    ItemWork.l = parent.l
    openflag = 1
  EndIf
  
  lpis.AdvTree_TVINSERTSTRUCT
  If openflag = #True
    pitem.AdvTree_TVITEM
    pitem\mask = #TVIF_CHILDREN | #TVIF_HANDLE
    pitem\hItem = ItemWork
    pitem\cChildren = 1
    SendMessage_(Gadget, #TVM_SETITEM, 0, @pitem)
    lpis\hParent = ItemWork
    lpis\hInsertAfter = ItemWork
  Else 
    lpis\hParent = SendMessage_(Gadget, #TVM_GETNEXTITEM, #TVGN_PARENT, ItemWork)
    lpis\hInsertAfter = ItemWork
  EndIf
  
  lpis\item\mask = #TVIF_TEXT 
  lpis\item\cchTextMax = Len(text)
  lpis\item\pszText = @text

  NewItem.l = SendMessage_(GadGet, #TVM_INSERTITEM, 0, @lpis)
  SendMessage_(GadGet, #TVM_ENSUREVISIBLE, 0, NewItem)
  
  ProcedureReturn NewItem.l
EndProcedure
Benutzeravatar
ts-soft
Beiträge: 22292
Registriert: 08.09.2004 00:57
Computerausstattung: Mainboard: MSI 970A-G43
CPU: AMD FX-6300 Six-Core Processor
GraKa: GeForce GTX 750 Ti, 2 GB
Memory: 16 GB DDR3-1600 - Dual Channel
Wohnort: Berlin

Beitrag von ts-soft »

:allright: danke für den schönen Code

Mal ein kleiner Tip: Sehe Dir mal das ObjectManagement von PB an, dann
kannste u.a. alles autom. freigeben lassen.

Notwendige Infos im LibrarySDK, sowie div. Snippet in beiden Foren, z.B.
CreateGadget, oder die DB Libs von Flype, engl. Forum

Gruß
Thomas
PureBasic 5.73 LTS | SpiderBasic 2.30 | Windows 10 Pro (x64) | Linux Mint 20.1 (x64)
Nutella hat nur sehr wenig Vitamine. Deswegen muss man davon relativ viel essen.
Bild
Benutzeravatar
neotoma
Beiträge: 202
Registriert: 13.09.2004 16:16
Kontaktdaten:

Beitrag von neotoma »

Gefällt mir so weit sehr gut.
Nur eine kleinigkeit, die immer übersehen wird, fehlt mir. Nämlich die Möglichkeit an jedes Item UserData(s) zu hängen. Gerade wenn man den Tree aus einer DB aufbaut, wünscht man sich die Id an jedem Item....

Mike
Alle Rechtschreibfehler unterliegen der GPL und dürfen frei kopiert und modifiziert werden.
Benutzeravatar
Kiffi
Beiträge: 10714
Registriert: 08.09.2004 08:21
Wohnort: Amphibios 9

Beitrag von Kiffi »

neotoma hat geschrieben:Gerade wenn man den Tree aus einer DB aufbaut, wünscht man sich die Id an jedem Item....
wenn nummerische Werte reichen, dann kannst Du SetGadgetItemData()
verwenden.

Grüße ... Kiffi
a²+b²=mc²
Benutzeravatar
Xaby
Beiträge: 2144
Registriert: 12.11.2005 11:29
Wohnort: Berlin + Zehdenick
Kontaktdaten:

Beitrag von Xaby »

Kann es sein, dass der Befehl nicht bei einem TreeGadget() fehlerfrei funktioniert?

Habe Werte zugewiesen und mit GetGadgetItemData() wieder abgerufen und nur NULL wieder bekommen ...

?????? :freak:
Kinder an die Macht http://scratch.mit.edu/
ShadowTurtle
Beiträge: 114
Registriert: 11.09.2004 07:58
Wohnort: Mannheim
Kontaktdaten:

Beitrag von ShadowTurtle »

Du bekommst den Handle zum Node zurück wenn Du eines erstellst. Du kannst diesen Wert also in deiner Struktur direkt abspeichern (vllt. als MyTreeNode.l ).

Ansonsten sollte GetGadgetItemData eigentlich Funktionieren, sofern Du nicht eine halb kaputte Purebasic Version (4.* Beta?) benutzt. Selbst der Entwickler gibt (inoffiziell) auf die Beta Version mittlerweile keine mindestens 50%ige saubere Lauffähigkeits-Garantie mehr.

Es kann aber auch sein (und empfinde ich eher als wahrscheinlicher) das dein Quellcode irgendein anderweitig auslösender Fehler enthält, welches weniger mit der Rückgabe sondern mehr mit der Programm-Logik zu tun hat.
Benutzeravatar
Kiffi
Beiträge: 10714
Registriert: 08.09.2004 08:21
Wohnort: Amphibios 9

Beitrag von Kiffi »

<OT>
ShadowTurtle hat geschrieben:Selbst der Entwickler gibt (inoffiziell) auf die Beta Version mittlerweile keine mindestens 50%ige saubere Lauffähigkeits-Garantie mehr.
interessant! Wo soll der Entwickler das (inoffiziell) geäußert haben?

</OT>
a²+b²=mc²
ShadowTurtle
Beiträge: 114
Registriert: 11.09.2004 07:58
Wohnort: Mannheim
Kontaktdaten:

Beitrag von ShadowTurtle »

<OT>

Das ist schon ziemlich lange her und ehrlich gesagt, ich Denke auch das dies nur ein Gerücht ist. Wäre aber in dieser Situation trotzdem wohl wirklich zutreffend. ;)

Aber in Anbetracht dessen das es in letzter Zeit wirklich viele Bug-Meldungen gab, welche sich erst seit den Beta Versionen finden lassen, schließe ich mich diesen "Gerücht" langsam an bzw. beginne am Gerücht zu glauben. :|

</OT>
Antworten