Seite 2 von 2

Re: BindGadgetEvent mit Parameter übergeben

Verfasst: 12.01.2014 20:17
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().

Re: BindGadgetEvent mit Parameter übergeben

Verfasst: 12.01.2014 20:23
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? :(

Re: BindGadgetEvent mit Parameter übergeben

Verfasst: 12.01.2014 20:29
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()

Re: BindGadgetEvent mit Parameter übergeben

Verfasst: 12.01.2014 20:39
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.

Re: BindGadgetEvent mit Parameter übergeben

Verfasst: 12.01.2014 20:39
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! :)

Re: BindGadgetEvent mit Parameter übergeben

Verfasst: 12.01.2014 20:43
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.

Re: BindGadgetEvent mit Parameter übergeben

Verfasst: 12.01.2014 21:02
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()

Re: BindGadgetEvent mit Parameter übergeben

Verfasst: 13.01.2014 08:01
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

Re: BindGadgetEvent mit Parameter übergeben

Verfasst: 14.01.2014 16:03
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