Seite 1 von 1

GetGadgetItemData - Strukturen und Listen speichern [gelöst]

Verfasst: 19.08.2014 18:47
von puretom
Hallo Forum!

Nach langer Abstinenz melde ich mich mal wieder im Forum mit einem Code-Schnippsel:

1. Erweiterte Daten in GadgetItemData speichern:

Dieser Code scheint zu funktionieren und seine Arbeit zu tun.
Da ich an sich kein großer "Pointerer" bin, bitte ich um Rückmeldung, ob der Code so passt.
Ich möchte euch bitten, ihn zu nutzen/testen und Fehler zu melden.
Für mich eine wichtige Frage ist auch: "Ist da ein Memory leak ???"

Code: Alles auswählen

;**********************************************************
;* Include file: Extended Gadget Item Data
;**********************************************************
; PureTom, 19.8.2014

EnableExplicit

Structure item_data
   item_int.i
   item_string.s
EndStructure

Procedure AddGadgetItemEx(gadget, item, text.s, image_id=0, flags=0)
   Protected *mem.item_data
   
   ; add gadget item
   AddGadgetItem(gadget, item, text.s, image_id, flags) 
   
   ; allocate pointer *mem with Memory of size of item_data 
   ; -> save *mem to GadgetItemData
   If item=-1: item=CountGadgetItems(gadget)-1: EndIf
   *mem = AllocateMemory(SizeOf(item_data))   
   SetGadgetItemData(gadget, item, *mem)
   
EndProcedure
Procedure RemoveGadgetItemEx(gadget, item)
   Protected *mem.item_data
   
   ; get the previos saved pointer *mem
   ; to free allocated memory
   *mem = GetGadgetItemData(gadget, item)
   FreeMemory(*mem)
   
   ; remove item
   RemoveGadgetItem(gadget, item)
   
EndProcedure
Procedure SetGadgetItemDataEx(gadget, item, *value.item_data)
   Protected *mem.item_data
   
   ; reads *mem pointer out of Gadget Item Data
   *mem = GetGadgetItemData(gadget, item)
   
   ; saves structure (indirect) in Gadget Item Data,
   ; direct in allocated memory *mem.item_data
   *mem\item_int = *value\item_int
   *mem\item_string = *value\item_string
   
EndProcedure

;**********************************************************
;* Test Program
;**********************************************************
Procedure Test_Program()
   Protected *mem.item_data, value.item_data, Event, i
   
   OpenWindow(0, #PB_Ignore, #PB_Ignore, 400, 200, "tests")
   ListViewGadget(1, 0, 0, 400, 200)
   
   ; Add items (allocate memory)
   AddGadgetItemEx(1, -1, "item 0")
   AddGadgetItemEx(1, -1, "item 1")
   AddGadgetItemEx(1, -1, "item 2")
   AddGadgetItemEx(1, -1, "item 3")

   ; set gadget item data in memory
   value\item_int = 0
   value\item_string = "ITEM 0"
   SetGadgetItemDataEx(1, 0, value)
   
   value\item_int = 1
   value\item_string = "ITEM 1"
   SetGadgetItemDataEx(1, 1, value)
   
   value\item_int = 2
   value\item_string = "ITEM 2"
   SetGadgetItemDataEx(1, 2, value)   
   
   value\item_int = 3
   value\item_string = "ITEM 3"
   SetGadgetItemDataEx(1, 3, value)
   
   ; windows event loop
   Repeat
      Event = WaitWindowEvent()
      
      If Event=#PB_Event_Gadget And EventGadget()=1
         
         Select EventType()
               
            Case #PB_EventType_LeftDoubleClick
               If GetGadgetState(1)>=0
                  *mem = GetGadgetItemData(1, GetGadgetState(1))
                  Debug "clicked: Pointer= "+Str(*mem)+", "+Str(*mem\item_int) + " - "+*mem\item_string
               EndIf
               
            Case #PB_EventType_RightClick
               If GetGadgetState(1)>=0
                  RemoveGadgetItemEx(1, GetGadgetState(1))         
               EndIf
               
         EndSelect
         
      EndIf   
      
      
   Until Event=#PB_Event_CloseWindow
EndProcedure

Test_Program()
; click in ListViewGadget :
; #PB_EventType_LeftDoubleClick -> shows all item_data
; #PB_EventType_RightClick -> delets selected (!) item

2. Linked Lists in GadgetItemData speichern:

Ich habe dann versucht, den Code auf Linked Lists zu erweitern, ab da scheitert alles völlig.

Die Stellen habe ich in der richtigen Reihenfolge nummeriert (auch im Code - man muss die Stellen auskommentieren) und zu Beginn auskommentiert:
  1. Das funktioniert, zeigt mir also, dass die Struktur übergeben wurde.
  2. Wenn ich das auskommentierte, erhalte ich die Fehlermeldung "Verknüpfte Liste nicht initialisiert"
  3. Nun, denke ich mir, dann fügen wir mal bei der Erstellung ein Listenelement hinzu.
    "Ungültiger Speicherzugriff. Lesefehler an ..." ist die Folge.
  4. Auch der Versuch, eine theoretisch erstellte, aber leere Liste mit ForEach abzuklappern, führt zu "Ungültiger Speicherzugriff. Lesefehler an ..."
Hier enden dann meine Künste und ich bitte euch, mir zu helfen.

LG Puretom.

Code: Alles auswählen

;**********************************************************
;* Include file: Extended Gadget Item Data (with LISTS)
;**********************************************************
; PureTom, 19.8.2014

EnableExplicit
Structure item_data
   item_int.i
   item_string.s
   List item_list.s()
EndStructure

Procedure AddGadgetItemEx(gadget, item, text.s, image_id=0, flags=0)
   Protected *mem.item_data
   
   ; add gadget item
   AddGadgetItem(gadget, item, text.s, image_id, flags) 
   
;    AddElement(*mem\item_list()) ; <--------------------- [3] "Ungültiger Speicherzugriff. Lesefehler an ..."
;    
;    ForEach *mem\item_list() ; <--------------------- [4] "Ungültiger Speicherzugriff. Lesefehler an ..."
;       Debug *mem\item_list()
;    Next

   ; allocate pointer *mem with Memory of size of item_data 
   ; -> save *mem to GadgetItemData
   If item=-1: item=CountGadgetItems(gadget)-1: EndIf
   *mem = AllocateMemory(SizeOf(item_data))   
   SetGadgetItemData(gadget, item, *mem)
   
EndProcedure
Procedure RemoveGadgetItemEx(gadget, item)
   Protected *mem.item_data
   
   ; get the previos saved pointer *mem
   ; to free allocated memory
   *mem = GetGadgetItemData(gadget, item)
   FreeMemory(*mem)
   
   ; remove item
   RemoveGadgetItem(gadget, item)
   
EndProcedure
Procedure SetGadgetItemDataEx(gadget, item, *value.item_data)
   Protected *mem.item_data
   
   ; reads *mem pointer out of Gadget Item Data
   *mem = GetGadgetItemData(gadget, item)
   
   ; saves structure (indirect) in Gadget Item Data,
   ; direct in allocated memory *mem.item_data
   *mem\item_int = *value\item_int
   *mem\item_string = *value\item_string
   
;    ForEach *value\item_list() ; <--------------------- [1] geht problemlos (siehe Debug-Ausgabe)
;       Debug *value\item_list();                        Liste wurde also problemlos übergeben
;    Next
   
;    CopyList(*value\item_list(), *mem\item_list()); <-------------- [2] "Verknüpfte Liste nicht initialisiert"
   
EndProcedure

;**********************************************************
;* Test Program
;**********************************************************
Procedure Test_Program()
   Protected *mem.item_data, value.item_data, Event, i
   
   OpenWindow(0, #PB_Ignore, #PB_Ignore, 400, 200, "tests")
   ListViewGadget(1, 0, 0, 400, 200)
   
   ; Add items (allocate memory)
   AddGadgetItemEx(1, -1, "item 0")
   AddGadgetItemEx(1, -1, "item 1")
   AddGadgetItemEx(1, -1, "item 2")
   AddGadgetItemEx(1, -1, "item 3")

   ; set gadget item data in memory
   value\item_int = 0
   
   value\item_string = "ITEM 0"
   AddElement(value\item_list())
   value\item_list()="ITEM 0 - List Element 0"
   AddElement(value\item_list())
   value\item_list()="ITEM 0 - List Element 1"
   SetGadgetItemDataEx(1, 0, value)
   ClearList(value\item_list())
   
   value\item_int = 1
   value\item_string = "ITEM 1"
   AddElement(value\item_list())
   value\item_list()="ITEM 1 - List Element 0"
   AddElement(value\item_list())
   value\item_list()="ITEM 1 - List Element 1"   
   SetGadgetItemDataEx(1, 1, value)
   ClearList(value\item_list())
   
   value\item_int = 2
   value\item_string = "ITEM 2"
   AddElement(value\item_list())
   value\item_list()="ITEM 2 - List Element 0"
   AddElement(value\item_list())
   value\item_list()="ITEM 2 - List Element 1"      
   SetGadgetItemDataEx(1, 2, value)   
   ClearList(value\item_list())
   
   value\item_int = 3
   value\item_string = "ITEM 3"
   AddElement(value\item_list())
   value\item_list()="ITEM 3 - List Element 0"
   AddElement(value\item_list())
   value\item_list()="ITEM 3 - List Element 1"      
   SetGadgetItemDataEx(1, 3, value)
   ClearList(value\item_list())
      
   ; windows event loop
   Repeat
      Event = WaitWindowEvent()
      
      If Event=#PB_Event_Gadget And EventGadget()=1
         
         Select EventType()
               
            Case #PB_EventType_LeftDoubleClick
               If GetGadgetState(1)>=0
                  *mem = GetGadgetItemData(1, GetGadgetState(1))
                  Debug "clicked: Pointer= "+Str(*mem)+", "+Str(*mem\item_int) + " - "+*mem\item_string
               EndIf
               
            Case #PB_EventType_RightClick
               If GetGadgetState(1)>=0
                  RemoveGadgetItemEx(1, GetGadgetState(1))         
               EndIf
               
         EndSelect
         
      EndIf   
      
      
   Until Event=#PB_Event_CloseWindow
EndProcedure

Test_Program()
; click in ListViewGadget :
; #PB_EventType_LeftDoubleClick -> shows all item_data
; #PB_EventType_RightClick -> delets selected (!) item

Re: GetGadgetItemData - Strukturen und Listen (??) speichern

Verfasst: 19.08.2014 19:13
von ts-soft
Fangen wir mal an :D
Im zweitem Code wurde der Memory nicht Initialisiert!
Hier mal die 2 betroffenen Funktionen:

Code: Alles auswählen

Procedure AddGadgetItemEx(gadget, item, text.s, image_id=0, flags=0)
   Protected *mem.item_data
   
   ; add gadget item
   AddGadgetItem(gadget, item, text.s, image_id, flags)
   
;    AddElement(*mem\item_list()) ; <--------------------- [3] "Ungültiger Speicherzugriff. Lesefehler an ..."
;   
;    ForEach *mem\item_list() ; <--------------------- [4] "Ungültiger Speicherzugriff. Lesefehler an ..."
;       Debug *mem\item_list()
;    Next

   ; allocate pointer *mem with Memory of size of item_data
   ; -> save *mem to GadgetItemData
   If item=-1: item=CountGadgetItems(gadget)-1: EndIf
   *mem = AllocateMemory(SizeOf(item_data))
   InitializeStructure(*mem, item_data)  
   SetGadgetItemData(gadget, item, *mem)
   
EndProcedure
Procedure RemoveGadgetItemEx(gadget, item)
   Protected *mem.item_data
   
   ; get the previos saved pointer *mem
   ; to free allocated memory
   *mem = GetGadgetItemData(gadget, item)
   ClearStructure(*mem, item_data)
   FreeMemory(*mem)
   
   ; remove item
   RemoveGadgetItem(gadget, item)
   
EndProcedure
Hab also InitialisizeStructure und ClearStructure hinzugefügt. Erklärung in der Hilfe.

Naja, ist noch mehr, aber gibt ja noch andere hier :wink:

Gruß
Thomas

Re: GetGadgetItemData - Strukturen und Listen (??) speichern

Verfasst: 19.08.2014 19:58
von puretom
@ts-soft!
Danke, danke, danke!

Habe nun einen funktionierenden Code, was mich zu 3 Fragen führt:
  1. Sind die Varianten [1] und [2] in meinem Code (abgesehen von Länge) technisch gleichwertig?
  2. Sollten InitializeStructure und ClearStructure auch in der Variante OHNE Lists eingeführt werden.
  3. Warum ja/nein? Und vor allem stelle ich diese Frage, weil ich aus der Hilfe leider nicht schlau werde, was InitializeStructure wirklich im Unterschied zu einem bloßen *mem = AllocateMemory(SizeOf(item_data)) anders/zusätzlich macht.
    Ich dachte, mit AllocateMemory und dem SizeOf(item_data) wäre die structure bereits im Speicher alloziert und somit hergestellt worden und der Platz PHYSISCH also bereits vorhanden.
    Wozu also InitializeStructure?
LG Puretom

Code: Alles auswählen

;**********************************************************
;* Include file: Extended Gadget Item Data (with LISTS)
;**********************************************************
; PureTom, 19.8.2014

EnableExplicit
Structure item_data
   item_int.i
   item_string.s
   List item_list.s()
EndStructure

Procedure AddGadgetItemEx(gadget, item, text.s, image_id=0, flags=0)
   Protected *mem.item_data
   
   ; add gadget item
   AddGadgetItem(gadget, item, text.s, image_id, flags) 
   
   ; allocate pointer *mem with Memory of size of item_data 
   ; -> save *mem to GadgetItemData
   If item=-1: item=CountGadgetItems(gadget)-1: EndIf
   *mem = AllocateMemory(SizeOf(item_data))
   InitializeStructure(*mem, item_data)    
   SetGadgetItemData(gadget, item, *mem)
   
EndProcedure
Procedure RemoveGadgetItemEx(gadget, item)
   Protected *mem.item_data
   
   ; get the previos saved pointer *mem
   ; to free allocated memory
   *mem = GetGadgetItemData(gadget, item)
   ClearStructure(*mem, item_data)   
   FreeMemory(*mem)
   
   ; remove item
   RemoveGadgetItem(gadget, item)
   
EndProcedure
Procedure SetGadgetItemDataEx(gadget, item, *value.item_data)
   Protected *mem.item_data
   
   ; reads *mem pointer out of Gadget Item Data
   *mem = GetGadgetItemData(gadget, item)
   
   ; saves structure (indirect) in Gadget Item Data,
   ; direct in allocated memory *mem.item_data
;    *mem\item_int = *value\item_int <-------------------- [1] ebenfalls funktionstüchtig 
;    *mem\item_string = *value\item_string
;    CopyList(*value\item_list(), *mem\item_list());
   
   CopyStructure(*value, *mem, item_data) ; <------- [2] damit wird die gesamte structure kopiert ???
   
EndProcedure

;**********************************************************
;* Test Program
;**********************************************************
Procedure Test_Program()
   Protected *mem.item_data, value.item_data, Event, i
   
   OpenWindow(0, #PB_Ignore, #PB_Ignore, 400, 200, "tests")
   ListViewGadget(1, 0, 0, 400, 200)
   
   ; Add items (allocate memory)
   AddGadgetItemEx(1, -1, "item 0")
   AddGadgetItemEx(1, -1, "item 1")
   AddGadgetItemEx(1, -1, "item 2")
   AddGadgetItemEx(1, -1, "item 3")

   ; set gadget item data in memory
   value\item_int = 0
   
   value\item_string = "ITEM 0"
   AddElement(value\item_list())
   value\item_list()="ITEM 0 - List Element 0"
   AddElement(value\item_list())
   value\item_list()="ITEM 0 - List Element 1"
   SetGadgetItemDataEx(1, 0, value)
   ClearList(value\item_list())
   
   value\item_int = 1
   value\item_string = "ITEM 1"
   AddElement(value\item_list())
   value\item_list()="ITEM 1 - List Element 0"
   AddElement(value\item_list())
   value\item_list()="ITEM 1 - List Element 1"   
   SetGadgetItemDataEx(1, 1, value)
   ClearList(value\item_list())
   
   value\item_int = 2
   value\item_string = "ITEM 2"
   AddElement(value\item_list())
   value\item_list()="ITEM 2 - List Element 0"
   AddElement(value\item_list())
   value\item_list()="ITEM 2 - List Element 1"      
   SetGadgetItemDataEx(1, 2, value)   
   ClearList(value\item_list())
   
   value\item_int = 3
   value\item_string = "ITEM 3"
   AddElement(value\item_list())
   value\item_list()="ITEM 3 - List Element 0"
   AddElement(value\item_list())
   value\item_list()="ITEM 3 - List Element 1"      
   SetGadgetItemDataEx(1, 3, value)
   ClearList(value\item_list())
      
   ; windows event loop
   Repeat
      Event = WaitWindowEvent()
      
      If Event=#PB_Event_Gadget And EventGadget()=1
         
         Select EventType()
               
            Case #PB_EventType_LeftDoubleClick
               If GetGadgetState(1)>=0
                  *mem = GetGadgetItemData(1, GetGadgetState(1))
                  Debug "clicked: Pointer= "+Str(*mem)+", "+Str(*mem\item_int) + " - "+*mem\item_string
                  ForEach *mem\item_list()
                     Debug "List Item "+ListIndex(*mem\item_list())+": "+Space(8)+*mem\item_list()
                  Next
               EndIf
               
            Case #PB_EventType_RightClick
               If GetGadgetState(1)>=0
                  RemoveGadgetItemEx(1, GetGadgetState(1))         
               EndIf
               
         EndSelect
         
      EndIf   
      
      
   Until Event=#PB_Event_CloseWindow
EndProcedure

Test_Program()
; click in ListViewGadget :
; #PB_EventType_LeftDoubleClick -> shows all item_data
; #PB_EventType_RightClick -> delets selected (!) item

Re: GetGadgetItemData - Strukturen und Listen (??) speichern

Verfasst: 19.08.2014 20:08
von ts-soft
zu 2:
Nein

zu 3:
Die Liste(), Map() oder das Array() wird Initialsiert. Das ist erforderlich, da der Memory dynamisch erstellt wurde.
Dies ist notwendig, um die Speicherbereiche wieder freigeben zu können, also die dadurch resultierenden.

Bei normalem Code ist das nicht erforderlich.

Re: GetGadgetItemData - Strukturen und Listen (??) speichern

Verfasst: 19.08.2014 20:41
von puretom
Danke!

Ich habe übrigens AllocateStructure hier in dieser Prozedur getestet, ist das gleichwertig?

Code: Alles auswählen

Procedure AddGadgetItemEx(gadget, item, text.s, image_id=0, flags=0)
   Protected *mem.item_data
   
   ; add gadget item
   AddGadgetItem(gadget, item, text.s, image_id, flags) 
   
   ; allocate pointer *mem with Memory of size of item_data 
   ; -> save *mem to GadgetItemData
   If item=-1: item=CountGadgetItems(gadget)-1: EndIf
   *mem = AllocateStructure(item_data);      <---- statt AllocateMemory
;    InitializeStructure(*mem, item_data)    <---- weg
   SetGadgetItemData(gadget, item, *mem)

EndProcedure
Ganz verstehe ich die Sache noch immer nicht, aber ich fasse zusammen, was ich verstanden habe:
  1. In einer normalen Struktur (mit einer normalen Variable verknüpft) mit einer List drinnen, schafft es PB hinzukommende Listen-Elemente einfach so wie durch Geisterhand dynamisch zu verwalten, Speicher zu löschen, ihn zur Verfügung zu stellen.
  2. sobald ich aber das über einen Pointer mache und einen Memory-Bereich mit AllocateMemory, schafft PB das Ganze nur nach einem InitializeStructure.
  3. allerdings, ein AllocateStructure statt einem AllocateMemory versetzt PB wieder in die Lage, alles so wie in Punkt 1 zu tun.
:o
Aber: dynamisch sind alle 3 Fälle, weil Listen ja immer dynamisch sind (kopfkratz)

Richtig?

Re: GetGadgetItemData - Strukturen und Listen (??) speichern

Verfasst: 19.08.2014 20:51
von ts-soft
Seit PB 5.30 kannst Du auch AllocateStructure und FreeStructure nutzen.

Code: Alles auswählen

Structure bla
  List a.i
EndStructure

Define bla.bla ; alles automatisch
Define *bla.bla ; alles dynnamisch
Gruß
Thomas

Re: GetGadgetItemData - Strukturen und Listen (??) speichern

Verfasst: 19.08.2014 21:10
von puretom
Ahh ja!

Danke, langsam dämmert es!

Um auf meine Frage von vorhin zurückzukommen, ist das einzelne Kopieren der Structure-Elemente exakt zu CopyStructure() gleichwertig?

Nun, meine Tests haben das gezeigt, somit vermute ich, das ist genau dasselbe.
CopyStructure() kopiert alle Elemente der Structure (also auch alle resultierenden Elemente und ersetzt auch das CopyList()).
Wie gesagt, beim Testen war es gleichwertig, aber man weiß ja nie (Memory-Leaks usw.) ;-)

Code: Alles auswählen

Procedure SetGadgetItemDataEx(gadget, item, *value.item_data)
   Protected *mem.item_data
   
   ; reads *mem pointer out of Gadget Item Data
   *mem = GetGadgetItemData(gadget, item)
   
   ; saves structure (indirect) in Gadget Item Data,
   ; direct in allocated memory *mem.item_data
;    *mem\item_int = *value\item_int <-------------------- [1] ebenfalls funktionstüchtig 
;    *mem\item_string = *value\item_string
;    CopyList(*value\item_list(), *mem\item_list());
   
   CopyStructure(*value, *mem, item_data) ; <------- [2] damit wird die gesamte structure kopiert ???
   
EndProcedure
Abgesehen von dieser kleinen Frage, der Code funktioniert!
Vielen Dank, ts-soft :D

LG Puretom

Re: GetGadgetItemData - Strukturen und Listen speichern [gel

Verfasst: 20.08.2014 23:17
von puretom
Weil mir langweilig war, noch einen drauf!

Obwohl gelöst, eine Variante mit einer Linked List als dynamischen Speicher für die Gadget Item Datas.
Für alle, die sich wie ich mit Memory-Pointern nicht wohlfühlen und nie recht wissen, ob diese Bereiche jetzt wirklich gelöscht wurden oder sich ein Memory Leak aufbaut.

Man kann hier beim Löschen wunderbar mit dem Debugger in der sog. Variablenliste zuschauen, wie die dazugehörigen LL Elemente tatsächlich verschwinden, wenn man mit Rechtsklick einen ListViewGadget-Eintrag löscht.

Viel Spaß damit!

LG Puretom

Code: Alles auswählen

;**********************************************************
;* Include file: Extended Gadget Item Data (with LISTS)
;**********************************************************
; with dynamic linked lists instead of dynamic memory
; Global is used
;----------------------------------------------------------

; PureTom, 20.8.2014

EnableExplicit
Structure item_data
   item_int.i
   item_string.s
   List item_list.s()
EndStructure
Global g_ItemData.item_data
Global NewList g_ItemDataList.item_data()


Procedure AddGadgetItemEx(gadget, item, text.s, image_id=0, flags=0)
   
   ; adds gadget item
   AddGadgetItem(gadget, item, text.s, image_id, flags) 
   If item=-1: item=CountGadgetItems(gadget)-1: EndIf
   
   ; Associate Linked List Element with Gadget Item
   AddElement(g_ItemDataList())
   SetGadgetItemData(gadget, item, @g_ItemDataList() )

EndProcedure
Procedure RemoveGadgetItemEx(gadget, item)
   Protected *list_element
   
   ; get the previous saved pointer *list_element
   ; to find associatet list element
   *list_element = GetGadgetItemData(gadget, item)
   ChangeCurrentElement(g_ItemDataList(), *list_element )
   
   ; remove List & Gadget Item
   DeleteElement(g_ItemDataList())   
   RemoveGadgetItem(gadget, item)
   
EndProcedure
Procedure SetGadgetItemDataEx(gadget, item)
   Protected *list_element
   
   ; get the previous saved pointer *list_element
   ; to find associatet list element
   ChangeCurrentElement(g_ItemDataList(), GetGadgetItemData(gadget, item) )
   
   ; copies the structure in linked list
   CopyStructure(g_ItemData, g_ItemDataList(), item_data) ; <--- 
   
EndProcedure

;**********************************************************
;* Test Program
;**********************************************************
Procedure Test_Program()
   Protected *mem, Event, i
   
   OpenWindow(0, #PB_Ignore, #PB_Ignore, 400, 200, "tests")
   ListViewGadget(1, 0, 0, 400, 200)
   
   ; Add items (allocate memory)
   AddGadgetItemEx(1, -1, "item 0")
   AddGadgetItemEx(1, -1, "item 1")
   AddGadgetItemEx(1, -1, "item 2")
   AddGadgetItemEx(1, -1, "item 3")

   ; set gadget item data in memory
   g_ItemData\item_int = 0
   g_ItemData\item_string = "ITEM 0"
   AddElement(g_ItemData\item_list())
   g_ItemData\item_list()="ITEM 0 - List Element 0"
   AddElement(g_ItemData\item_list())
   g_ItemData\item_list()="ITEM 0 - List Element 1"
   SetGadgetItemDataEx(1, 0)
   ClearList(g_ItemData\item_list())
   
   g_ItemData\item_int = 1
   g_ItemData\item_string = "ITEM 1"
   AddElement(g_ItemData\item_list())
   g_ItemData\item_list()="ITEM 1 - List Element 0"
   AddElement(g_ItemData\item_list())
   g_ItemData\item_list()="ITEM 1 - List Element 1"   
   SetGadgetItemDataEx(1, 1)
   ClearList(g_ItemData\item_list())
   
   g_ItemData\item_int = 2
   g_ItemData\item_string = "ITEM 2"
   AddElement(g_ItemData\item_list())
   g_ItemData\item_list()="ITEM 2 - List Element 0"
   AddElement(g_ItemData\item_list())
   g_ItemData\item_list()="ITEM 2 - List Element 1"      
   SetGadgetItemDataEx(1, 2)
   ClearList(g_ItemData\item_list())
   
   g_ItemData\item_int = 3
   g_ItemData\item_string = "ITEM 3"
   AddElement(g_ItemData\item_list())
   g_ItemData\item_list()="ITEM 3 - List Element 0"
   AddElement(g_ItemData\item_list())
   g_ItemData\item_list()="ITEM 3 - List Element 1"      
   SetGadgetItemDataEx(1, 3)
   ClearList(g_ItemData\item_list())
      
   ; windows event loop
   Repeat
      Event = WaitWindowEvent()
      
      If Event=#PB_Event_Gadget And EventGadget()=1
         
         Select EventType()
               
            Case #PB_EventType_LeftDoubleClick
               If GetGadgetState(1)>=0
                  *mem = GetGadgetItemData(1, GetGadgetState(1))
                  ChangeCurrentElement(g_ItemDataList(), *mem)
                  Debug "clicked: Pointer= "+Str(@g_ItemDataList())+", "+Str(g_ItemDataList()\item_int) + " - "+g_ItemDataList()\item_string
                  ForEach g_ItemDataList()\item_list()
                     Debug "List Item "+ListIndex(g_ItemDataList()\item_list())+": "+Space(8)+g_ItemDataList()\item_list()
                  Next
               EndIf
               
            Case #PB_EventType_RightClick
               If GetGadgetState(1)>=0
                  RemoveGadgetItemEx(1, GetGadgetState(1))         
               EndIf
               
         EndSelect
         
      EndIf   
      
      
   Until Event=#PB_Event_CloseWindow
EndProcedure

Test_Program()
; click in ListViewGadget :
; #PB_EventType_LeftDoubleClick -> shows all item_data
; #PB_EventType_RightClick -> delets selected (!) item