BindGadgetEvent mit Parameter übergeben

Für allgemeine Fragen zur Programmierung mit PureBasic.
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

Re: BindGadgetEvent mit Parameter übergeben

Beitrag von ts-soft »

edel hat geschrieben:und das hier schon erwaehnte PostEvent kann es ja auch.
Die mit PostEvent gesendeten Daten können ja auch im Callback ausgewertet werde, ohne
das hierfür ein Parameter nötig wäre, siehe z.B. EventData().
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
Ameisen23
Beiträge: 50
Registriert: 19.10.2013 12:04

Re: BindGadgetEvent mit Parameter übergeben

Beitrag von Ameisen23 »

Ich danke euch für die Codes, edel und NicTheQuick! :)

SetGadgetData ist eine sehr gute Idee, Danke! Ich habe versucht um mehrere Werte zu übergeben eine List mit Struktur zu übergeben. So kann ich auch mehrere Werte übergeben. Mein COde funktioniert aber nur teilweise und nicht ganz zuverlässig aber ich weiss leider nicht warum...

Code: Alles auswählen

EnableExplicit

Define Event

Structure mystructure
  value1.s
  value2.s
EndStructure

Procedure ButtonHandler()
  Protected gadget
  Protected *mystructure.mystructure
  
  gadget = EventGadget()
  
  *mystructure.mystructure = GetGadgetData(gadget)
  
  Debug *mystructure\value1
  Debug *mystructure\value2

  
EndProcedure



Procedure mywindow()
  Protected NewList mylist.mystructure()
  
  OpenWindow(1, 0, 0, 400, 300, "my window", #PB_Window_WindowCentered, WindowID(0))
  
  ButtonGadget(0, 10, 10, 180, 50, "Click me" + Chr(13) + "hier hat er probleme beim auslesen", #BS_MULTILINE)
  ButtonGadget(1, 100, 100, 180, 30, "Click me")
  ButtonGadget(2, 100, 200, 180, 30, "end")
  
  
  AddElement(mylist())
  mylist()\value1 = "my first item"
  mylist()\value2 = "my first item value"
  
  SetGadgetData(0, @mylist())
  
  BindGadgetEvent(0, @ButtonHandler())
  
  AddElement(mylist())
  mylist()\value1 = "my seccond item"
  mylist()\value2 = "my seccond item value"
  
  SetGadgetData(1, @mylist())
  
  BindGadgetEvent(1, @ButtonHandler())
  
EndProcedure

OpenWindow(0, 100, 100, 500, 400, "Click test", #PB_Window_SystemMenu)

ButtonGadget(3, 10, 10, 180, 30, "open my window", 0)


Repeat
  Event = WaitWindowEvent()
  If Event = #PB_Event_Gadget
      Select EventGadget()
        Case 2
          CloseWindow(1)
        Case 3
          mywindow()
      EndSelect
    EndIf
Until Event = #PB_Event_CloseWindow
Wenn ich auf den 1. Button klicke dann bekomme ich:

Code: Alles auswählen

Ä
my first item value
Das "Ä" ist aber falsch. Wenn ich auf den 2. Button klicke, dann...

Code: Alles auswählen

my seccond item
my seccond item value
Dann wurden beide Struktur Elemente richtig ausgelesen aber warum beim 1. Button nicht? Was mache ich falsch? :(
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8808
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 64 GB DDR4-3200
Ubuntu 24.04.2 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken

Re: BindGadgetEvent mit Parameter übergeben

Beitrag von NicTheQuick »

Nachdem deine Procedure 'mywindow()' verlassen wurde, gibt es die Liste 'mylist.mystructure' nicht mehr und somit auch keine ihrer Elemente mehr. Das heißt die Pointer, die du in 'ButtonHandler' erhälst, sind nicht mehr gültig. Dann ist es nur noch Zufall, ob der selbe Wert wie vorher drin steht oder nicht.
Die einfachste Lösung wäre die Liste global zu machen, also am Anfang deines Codes schreiben:

Code: Alles auswählen

Global NewList mylist.mystructure()
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

Re: BindGadgetEvent mit Parameter übergeben

Beitrag von ts-soft »

NicTheQuick hat geschrieben:Die einfachste Lösung wäre die Liste global zu machen, also am Anfang deines Codes schreiben:

Code: Alles auswählen

Global NewList mylist.mystructure()
Stimmt, das macht aber das Gedöns mit SetGadgetData überflüssig.
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
Ameisen23
Beiträge: 50
Registriert: 19.10.2013 12:04

Re: BindGadgetEvent mit Parameter übergeben

Beitrag von Ameisen23 »

Ach so ich verstehe. Danke fürs erklären. Hm ich versuche mein Code immer möglichs so zu gestalten das ich keine globale Vars oder andere Sachen habe weil ich es unsauber finde wenn zb. List überall zugreifbar ist. Wenn ich es global machen würde dann hätte ich nur die Struktur ohne List Verknüpfung gemacht dann ist es auch global nur das will ich nich. Ich werde einfach eure Codes direkt nehmen. Danke nochmal für die Hilfen! :)
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8808
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 64 GB DDR4-3200
Ubuntu 24.04.2 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken

Re: BindGadgetEvent mit Parameter übergeben

Beitrag von NicTheQuick »

ts-soft hat geschrieben:<snip>
Stimmt, das macht aber das Gedöns mit SetGadgetData überflüssig.
Naja, finde ich jetzt nicht. Immerhin kriegt man dann im Callback direkt das Element, das man haben will, und muss nicht zuerst noch durch die Liste iterieren. In dem Fall würde die Liste ja auch nur als alternative Speicherverwaltung für eine gleichbleibende Struktur verwendet. Also ich nehme mal an, dass Ameisen23 noch mehr als nur ein Element hinzufügen wollte.
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

Re: BindGadgetEvent mit Parameter übergeben

Beitrag von ts-soft »

Ameisen23 hat geschrieben:Hm ich versuche mein Code immer möglichs so zu gestalten das ich keine globale Vars oder andere Sachen habe weil ich es unsauber finde wenn zb. List überall zugreifbar ist... :)
Da gibt es noch Shared, also ist die List nur dort gültig, wo sie geshared wird + im MainScope,
den man so gestalten kann, das er fast leer ist :wink:

Code: Alles auswählen

EnableExplicit

Structure mystructure
  value1.s
  value2.s
EndStructure

NewList mylist.mystructure()

Procedure ButtonHandler()
  Protected gadget
  Shared mylist.mystructure()
 
  gadget = EventGadget()
 
  ChangeCurrentElement(mylist(), GetGadgetData(gadget))
 
  Debug mylist()\value1
  Debug mylist()\value2

 
EndProcedure



Procedure mywindow()
  Shared mylist.mystructure()
 
  OpenWindow(1, 0, 0, 400, 300, "my window", #PB_Window_WindowCentered, WindowID(0))
 
  ButtonGadget(0, 10, 10, 180, 50, "Click me" + Chr(13) + "hier hat er probleme beim auslesen", #BS_MULTILINE)
  ButtonGadget(1, 100, 100, 180, 30, "Click me")
  ButtonGadget(2, 100, 200, 180, 30, "end")
 
 
  AddElement(mylist())
  mylist()\value1 = "my first item"
  mylist()\value2 = "my first item value"
 
  SetGadgetData(0, @mylist())
 
  BindGadgetEvent(0, @ButtonHandler())
 
  AddElement(mylist())
  mylist()\value1 = "my seccond item"
  mylist()\value2 = "my seccond item value"
 
  SetGadgetData(1, @mylist())
 
  BindGadgetEvent(1, @ButtonHandler())
 
EndProcedure

Procedure Main()
  Define Event
  
  OpenWindow(0, 100, 100, 500, 400, "Click test", #PB_Window_SystemMenu)
  
  ButtonGadget(3, 10, 10, 180, 30, "open my window", 0)
  
  
  Repeat
    Event = WaitWindowEvent()
    If Event = #PB_Event_Gadget
        Select EventGadget()
          Case 2
            CloseWindow(1)
          Case 3
            mywindow()
        EndSelect
      EndIf
  Until Event = #PB_Event_CloseWindow
EndProcedure

Main()
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
Bisonte
Beiträge: 2467
Registriert: 01.04.2007 20:18

Re: BindGadgetEvent mit Parameter übergeben

Beitrag von Bisonte »

Wenn man eine Struktur per SetGadgetData anhängen will, sollte man einen Speicherblock dafür bereitstellen.
Um deinen Code nicht zu gross zu verändern nur eine CopyToGadget Prozedur eingefügt und den aufruf 2x dazu....

Code: Alles auswählen

EnableExplicit

Define Event

Structure mystructure
  value1.s
  value2.s
EndStructure

Procedure ButtonHandler()
  
  Protected *p.mystructure
  Protected Gadget = EventGadget()
  
  *p = GetGadgetData(Gadget)

  If *p
    Debug *p\value1
    Debug *p\value2
  EndIf
    
EndProcedure

Procedure CopyToGadget(Gadget, *mydata.mystructure)
  
  Protected *p.mystructure
  
  If IsGadget(Gadget)
    *p = GetGadgetData(Gadget) ; <- Aus dem Gadget auslesen
    If Not *p ; Ist nix zum auslesen drin, also was erstellen
      *p = AllocateMemory(SizeOf(mystructure))
    EndIf
    If Not *p : ProcedureReturn #False : EndIf ; Speicher kann nicht erstellt werden, also raus hier
    SetGadgetData(Gadget, *p) ; Speicher dem Gadget zuweisen
    CopyStructure(*mydata, *p, mystructure) ; die Struktur von *mydata in den Speicher kopieren
    ProcedureReturn #True
  EndIf
  
EndProcedure

Procedure mywindow()
  
  Protected NewList mylist.mystructure()
  
  OpenWindow(1, 0, 0, 400, 300, "my window", #PB_Window_WindowCentered, WindowID(0))
 
  ButtonGadget(0, 10, 10, 180, 50, "Click me" + Chr(13) + "hier hat er probleme beim auslesen", #BS_MULTILINE)
  ButtonGadget(1, 100, 100, 180, 30, "Click me")
  ButtonGadget(2, 100, 200, 180, 30, "end")
  
  AddElement(mylist())
  mylist()\value1 = "my first item"
  mylist()\value2 = "my first item value"
  
  CopyToGadget(0, @mylist())
  BindGadgetEvent(0, @ButtonHandler())
  
  AddElement(mylist())
  mylist()\value1 = "my seccond item"
  mylist()\value2 = "my seccond item value"
  
  CopyToGadget(1, @mylist())
  BindGadgetEvent(1, @ButtonHandler())
  
EndProcedure

OpenWindow(0, 100, 100, 500, 400, "Click test", #PB_Window_SystemMenu)

ButtonGadget(3, 10, 10, 180, 30, "open my window", 0)

Repeat
  Event = WaitWindowEvent()
  If Event = #PB_Event_Gadget
      Select EventGadget()
        Case 2
          CloseWindow(1)
        Case 3
          mywindow()
      EndSelect
    EndIf
Until Event = #PB_Event_CloseWindow
PureBasic 6.21 (Windows x86/x64) | Windows11 Pro x64 | AsRock B850 Steel Legend Wifi | R7 9800x3D | 64GB RAM | GeForce RTX 5080 | ThermaltakeView 270 TG ARGB | build by vannicom​​
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

Re: BindGadgetEvent mit Parameter übergeben

Beitrag von ts-soft »

Hier noch eine, wie ich denke, elegante Lösung mit Modul:

Code: Alles auswählen

; based on code by fred: http://www.purebasic.fr/english/viewtopic.php?p=323668#p323668

DeclareModule Props
  Declare.i GetProp(Gadget, Name.s)             ; Get a property from the given #Gadget. Returns 0 if the property does not exist
  Declare.s GetPropStr(Gadget, Name.s)          ; Get a propertystring from the given #Gadget. Returns "" if the property does not exist
  Declare   SetProp(Gadget, Name.s, Value)      ; Set a property on the given #Gadget 
  Declare   SetPropStr(Gadget, Name.s, Value.s) ; Set a propertystring on the given #Gadget 
  Declare   RemoveProp(Gadget, Name.s)          ; Remove a property from the given #Gadget (if it exists)
  Declare   RemoveAllProps(Gadget)              ; Remove all properties (and the map) from a given #Gadget.
EndDeclareModule

Module Props
  EnableExplicit
  
  Structure PropType
    val.i
    text.s
  EndStructure
  
  Structure PropMap
    Map PropName.PropType()
  EndStructure
  
  Global NewMap Props.PropMap()
  
  Procedure GetProp(Gadget, Name.s)
    Name = UCase(Name)
    If Props(Str(Gadget))
      ProcedureReturn Props()\PropName(Name)\val
    EndIf
  EndProcedure

  Procedure.s GetPropStr(Gadget, Name.s)
    Name = UCase(Name)
    If Props(Str(Gadget))
      ProcedureReturn Props()\PropName(Name)\text
    EndIf
  EndProcedure
   
  Procedure SetProp(Gadget, Name.s, Value)
    Name = UCase(Name)
    Props(Str(Gadget))\PropName(Name)\val = Value
  EndProcedure

  Procedure SetPropStr(Gadget, Name.s, Value.s)
    Name = UCase(Name)
    Props(Str(Gadget))\PropName(Name)\text = Value
  EndProcedure
  
  Procedure RemoveProp(Gadget, Name.s)
    Name = UCase(Name)
    If Props(Str(Gadget))
      DeleteMapElement(Props()\PropName(), Name)
    EndIf    
  EndProcedure
  
  Procedure RemoveAllProps(Gadget)
    DeleteMapElement(Props(), Str(Gadget))
  EndProcedure
EndModule

CompilerIf #PB_Compiler_IsMainFile

EnableExplicit

CompilerIf Not #PB_Compiler_OS = #PB_OS_Windows
  #BS_MULTILINE = 0
CompilerEndIf

UseModule Props

Procedure ButtonHandler()
  Protected gadget
 
  gadget = EventGadget()
 
  Debug GetPropStr(gadget, "value1")
  Debug GetPropStr(gadget, "value2")
 
EndProcedure


Procedure mywindow()
 
  If IsWindow(1)
    UnbindGadgetEvent(0, @ButtonHandler())
    RemoveAllProps(0)
    UnbindGadgetEvent(1, @ButtonHandler())
    RemoveAllProps(1)   
  EndIf
 
  OpenWindow(1, 0, 0, 400, 300, "my window", #PB_Window_WindowCentered, WindowID(0))
 
  ButtonGadget(0, 10, 10, 180, 50, "Click me" + Chr(13) + "hier hat er probleme beim auslesen", #BS_MULTILINE)
  ButtonGadget(1, 100, 100, 180, 30, "Click me")
  ButtonGadget(2, 100, 200, 180, 30, "end")
 
  SetPropStr(0, "value1", "my first item")
  SetPropStr(0, "value2", "my first item value")
 
  BindGadgetEvent(0, @ButtonHandler())

  SetPropStr(1, "value1", "my seccond item")
  SetPropStr(1, "value2", "my seccond item value")
 
  BindGadgetEvent(1, @ButtonHandler())
 
EndProcedure

Procedure Main()
  Protected Event
 
  OpenWindow(0, 100, 100, 500, 400, "Click test", #PB_Window_SystemMenu)
 
  ButtonGadget(3, 10, 10, 180, 30, "open my window", 0)
 
 
  Repeat
    Event = WaitWindowEvent()
    If Event = #PB_Event_Gadget
        Select EventGadget()
          Case 2
            CloseWindow(1)
          Case 3
            mywindow()
        EndSelect
      EndIf
  Until Event = #PB_Event_CloseWindow
EndProcedure

Main()

CompilerEndIf 
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
Antworten