Ein Bug? [gelöst]
Verfasst: 12.05.2014 11:08
Hi.
Uns lässt die PB-Hilfe in dem Glauben, die dynamische Gadget-Nummern-Zuweisung sei unique, also einzigartig - jeder Gadget, der dynamisch erstellt wird, habe eine eigene Nummer, die kein anderer Gadget haben kann.
Nun habe ich eben ein Programm geschrieben, in dem genau dieses Paradigma nicht erfüllt wird.
Aber zunächst zu dem Programm: Ich soll Begriffe in einer Netz- oder Baumstruktur ordnen. Dazu habe ich ein Programm geschrieben, dass ich unten gepostet habe. Dieses Programm stellt "Knoten" als Fenster auf dem Desktop dar. Jeder "Knoten" kann Begriffe beinhalten. Wird ein Begriff von mehreren Knoten gehalten, wird dies in allen betroffenen Knoten angezeigt.
Es gibt also eine dynamische Fensterverwaltung (alle Fenster sind "Knoten", bis auf den "Knotenmanager", die in der Struktur NODE in der Liste Nodes() gespeichert werden) und jedes Fenster kann ein "Add Window" aufrufen; ein Fenster, dass das Einbinden neuer Begriffe erlaubt. (Da diese Begriffe in einer csv-Datei gespeichert sind, habe ich Euch mal einen kleinen Ausschnitt der csv-Datei mitgeliefert.)
Im Programm macht sich der Fehler nur dadurch bemerkbar, dass beim Aufruf eines Buttons im Add Window plötzlich das Event eines anderen Buttons getriggert wird - ich dachte, ich sehe nicht richtig!
Hier erstmal das Programm:
Und beim Klick auf "CSV-Datei laden..." im "Add Window" wird plötzlich folgendes angezeigt:

Dabei habe ich den entsprechenden Button "Nodes()\addwndbntwo" gar nicht geklickt!
Eine Analyse der dynamisch verteilten Gadget-Nummern im Variablen-Viewer der PB-IDE ergab dann folgende Erkenntniss:

Wie ganz unten im Bild zu sehen ist hat "Nodes(:1:)\addwndli", das ListIconGadget im "Add Window" des zweiten Knoten, dieselbe Nummer wie "Nodes(:0:)\addwndbntwo", der Hinzufügen-Button im "AddWindow" des ersten Knotens.
Wie kann das sein?
/EDIT: Fehler gefunden. Eine dynamisch erzeugte Gadget-Nummer wird natürlich nur solange vorgehalten, wie der Gadget geöffnet ist. Da die "Add Windows" dynamisch erzeugt und auch gleich wieder geschlossen werden kann eine Doppelbelegung auftreten. Ich muss alle Add Windows im Vorraus erzeugen und dann nur noch dynamisch einblenden.
Sorry für diesen Thread.
Uns lässt die PB-Hilfe in dem Glauben, die dynamische Gadget-Nummern-Zuweisung sei unique, also einzigartig - jeder Gadget, der dynamisch erstellt wird, habe eine eigene Nummer, die kein anderer Gadget haben kann.
Nun habe ich eben ein Programm geschrieben, in dem genau dieses Paradigma nicht erfüllt wird.
Aber zunächst zu dem Programm: Ich soll Begriffe in einer Netz- oder Baumstruktur ordnen. Dazu habe ich ein Programm geschrieben, dass ich unten gepostet habe. Dieses Programm stellt "Knoten" als Fenster auf dem Desktop dar. Jeder "Knoten" kann Begriffe beinhalten. Wird ein Begriff von mehreren Knoten gehalten, wird dies in allen betroffenen Knoten angezeigt.
Es gibt also eine dynamische Fensterverwaltung (alle Fenster sind "Knoten", bis auf den "Knotenmanager", die in der Struktur NODE in der Liste Nodes() gespeichert werden) und jedes Fenster kann ein "Add Window" aufrufen; ein Fenster, dass das Einbinden neuer Begriffe erlaubt. (Da diese Begriffe in einer csv-Datei gespeichert sind, habe ich Euch mal einen kleinen Ausschnitt der csv-Datei mitgeliefert.)
Im Programm macht sich der Fehler nur dadurch bemerkbar, dass beim Aufruf eines Buttons im Add Window plötzlich das Event eines anderen Buttons getriggert wird - ich dachte, ich sehe nicht richtig!
Hier erstmal das Programm:
Code: Alles auswählen
Structure ENTRY
word$
List alsoin$()
EndStructure
Structure NODE
addwnd.i
addwndbnone.i
addwndbntwo.i
addwndli.i
bnone.i
bntwo.i
H.w
li.i
Name$
Node.i
ppm.i
S.i
wnd.i
W.w
X.w
Y.w
List Entries.ENTRY()
EndStructure
Global Manager
Global NewList Nodes.NODE()
Procedure FindAlsoIns()
ForEach Nodes()
ForEach Nodes()\Entries()
CurrentNode = ListIndex(Nodes())
CurrentEntry = ListIndex(Nodes()\Entries())
ClearList(Nodes()\Entries()\alsoin$())
Word$ = Nodes()\Entries()\word$
AlsoIn$ = ""
ForEach Nodes()
If Not ListIndex(Nodes()) = CurrentNode
ForEach Nodes()\Entries()
If Nodes()\Entries()\word$ = Word$
AlsoIn$ + Nodes()\Name$ + ";"
EndIf
Next
EndIf
Next
SelectElement(Nodes(), CurrentNode)
SelectElement(Nodes()\Entries(), CurrentEntry)
For Index = 0 To CountString(AlsoIn$, ";")
AddElement(Nodes()\Entries()\alsoin$())
Nodes()\Entries()\alsoin$() = StringField(AlsoIn$, Index + 1, ";")
Next
Next
Next
EndProcedure
Procedure CreateNewNode(*Node.NODE)
*Node\wnd = OpenWindow(#PB_Any, *Node\X, *Node\Y, *Node\W, *Node\H, *Node\Name$, #PB_Window_MinimizeGadget|#PB_Window_SystemMenu|#PB_Window_SizeGadget|#PB_Window_MaximizeGadget, WindowID(Manager))
*Node\bnone = ButtonGadget(#PB_Any, 0, 0, 100, 20, "Hinzufügen...")
*Node\bntwo = ButtonGadget(#PB_Any, 100, 0, 80, 20, "Entfernen")
*Node\li = ListIconGadget(#PB_Any, 0, 20, 240, 300, "Begriff", 100, #PB_ListIcon_AlwaysShowSelection|#PB_ListIcon_FullRowSelect)
AddGadgetColumn(*Node\li, 1, "auch in", 115)
*Node\ppm = CreatePopupMenu(#PB_Any)
MenuItem(001, "Kopieren")
ForEach *Node\Entries()
AlsoIn$ = ""
For Index = 1 To ListSize(*Node\Entries()\alsoin$())
SelectElement(*Node\Entries()\alsoin$(), Index - 1)
If AlsoIn$
AlsoIn$ + "; " + *Node\Entries()\alsoin$()
Else
AlsoIn$ + *Node\Entries()\alsoin$()
EndIf
Next
AddGadgetItem(*Node\li, #PB_Any, *Node\Entries()\word$ + Chr(10) + AlsoIn$)
Next
SetWindowState(*Node\wnd, *Node\S)
EndProcedure
Procedure AddWindow()
; CurrentNode = ListIndex(Nodes())
; ForEach Nodes()
; If IsWindow(Nodes()\addwnd)
; CloseWindow(Nodes()\addwnd)
; EndIf
; Next
; SelectElement(Nodes(), CurrentNode)
Nodes()\addwnd = OpenWindow(#PB_Any, 0, 0, 600, 360, "Add Window - " + Nodes()\Name$, #PB_Window_SystemMenu|#PB_Window_ScreenCentered|#PB_Window_SizeGadget|#PB_Window_MinimizeGadget|#PB_Window_MaximizeGadget, WindowID(Manager))
Nodes()\addwndli = ListIconGadget(#PB_Any, 20, 40, 360, 180, "Begriff", 120, #PB_ListIcon_FullRowSelect|#PB_ListIcon_AlwaysShowSelection)
AddGadgetColumn(Nodes()\addwndli, 1, "in Subkategorie", 120)
AddGadgetColumn(Nodes()\addwndli, 2, "in Pattern", 120)
AddGadgetColumn(Nodes()\addwndli, 3, "Zugeordnet", 100)
Nodes()\addwndbnone = ButtonGadget(#PB_Any, 20, 10, 100, 20, "Liste laden (*.csv)...")
Nodes()\addwndbntwo = ButtonGadget(#PB_Any, 300, 10, 80, 20, "Auswählen", #PB_Button_Default)
EndProcedure
Procedure RemoveEntry()
If Not GetGadgetState(Nodes()\li) = #PB_Any
SelectElement(Nodes()\Entries(), GetGadgetState(Nodes()\li))
DeleteElement(Nodes()\Entries())
RemoveGadgetItem(Nodes()\li, GetGadgetState(Nodes()\li))
FindAlsoIns()
EndIf
EndProcedure
Manager = OpenWindow(#PB_Any, 5, 5, 200, 80, "Knotenmanager", #PB_Window_SystemMenu|#PB_Window_MinimizeGadget)
Button_Neu = ButtonGadget(#PB_Any, 0, 0, 200, 20, "Neuer Knoten")
;- XML-Datei lesen
Xml = LoadXML(#PB_Any, GetHomeDirectory() + "standard.xml")
If Xml
MainNode = MainXMLNode(Xml)
ChildNode = ChildXMLNode(MainNode)
While ChildNode
AddElement(Nodes())
Nodes()\Node = ChildNode
If ExamineXMLAttributes(ChildNode)
While NextXMLAttribute(ChildNode)
Select XMLAttributeName(ChildNode)
Case "Name"
Nodes()\Name$ = XMLAttributeValue(ChildNode)
Case "X"
Nodes()\X = Val(XMLAttributeValue(ChildNode))
Case "Y"
Nodes()\Y = Val(XMLAttributeValue(ChildNode))
Case "W"
Nodes()\W = Val(XMLAttributeValue(ChildNode))
Case "H"
Nodes()\H = Val(XMLAttributeValue(ChildNode))
Case "S"
Nodes()\S = Val(XMLAttributeValue(ChildNode))
EndSelect
Wend
EndIf
EntryNode = ChildXMLNode(ChildNode)
While EntryNode
AddElement(Nodes()\Entries())
If ExamineXMLAttributes(EntryNode)
While NextXMLAttribute(EntryNode)
Select XMLAttributeName(EntryNode)
Case "word"
Nodes()\Entries()\word$ = XMLAttributeValue(EntryNode)
EndSelect
Wend
EndIf
EntryNode = NextXMLNode(EntryNode)
Wend
ChildNode = NextXMLNode(ChildNode)
Wend
FindAlsoIns()
ForEach Nodes()
CreateNewNode(Nodes())
Next
EndIf
;-
Repeat
eventid = WaitWindowEvent(#True)
Select eventid
Case #PB_Event_CloseWindow
If EventWindow() = Manager
Break
Else
ForEach Nodes()
If Nodes()\wnd = EventWindow()
If MessageRequester("Knoten löschen", "Möchten Sie diesen Knoten und seinen gesammten Inhalt wirklich löschen?", #PB_MessageRequester_YesNoCancel) = #PB_MessageRequester_Yes
CloseWindow(Nodes()\wnd)
DeleteElement(Nodes())
Break
EndIf
EndIf
If Nodes()\addwnd = EventWindow()
CloseWindow(Nodes()\addwnd)
Break
EndIf
Next
EndIf
Case #PB_Event_Gadget
Select EventGadget()
Case Button_Neu
AddElement(Nodes())
Nodes()\Name$ = InputRequester("Neuer Knoten", "Wie soll der Knoten heißen?", "Neuer Knoten")
If Nodes()\Name$
Nodes()\W = 320
Nodes()\H = 240
CreateNewNode(Nodes())
Else
DeleteElement(Nodes())
EndIf
EndSelect
ForEach Nodes()
If EventGadget() = Nodes()\addwndbnone
FileName$ = OpenFileRequester("", "", "CSV-Datei (*.csv)|*.csv|Alle Dateien (*.*)|*.*", 0)
If ReadFile(0, FileName$)
While Not Eof(0)
Vorhanden$ = ""
ReadString$ = ReadString(0)
CurrentNode = ListIndex(Nodes())
ForEach Nodes()
CurrentEntry = ListIndex(Nodes()\Entries())
ForEach Nodes()\Entries()
If Nodes()\Entries()\word$ = StringField(ReadString$, 4, ";")
Vorhanden$ = "zugeordnet"
Break
EndIf
Next
If Not CurrentEntry = #PB_Any
SelectElement(Nodes()\Entries(), CurrentEntry)
EndIf
Next
If Not CurrentNode = #PB_Any
SelectElement(Nodes(), CurrentNode)
EndIf
AddGadgetItem(Nodes()\addwndli, #PB_Any, StringField(ReadString$, 4, ";") + Chr(10) + StringField(ReadString$, 2, ";") + Chr(10) + StringField(ReadString$, 3, ";") + Chr(10) + Vorhanden$)
Wend
CloseFile(0)
EndIf
Break
ElseIf EventGadget() = Nodes()\addwndbntwo
AddElement(Nodes()\Entries())
Nodes()\Entries()\word$ = GetGadgetItemText(Nodes()\addwndli, GetGadgetState(Nodes()\addwndli))
CloseWindow(Nodes()\addwnd)
AddGadgetItem(Nodes()\li, #PB_Any, Nodes()\Entries()\word$)
FindAlsoIns()
Gosub ResetLi
Break
ElseIf EventGadget() = Nodes()\bnone
AddWindow()
Break
ElseIf EventGadget() = Nodes()\bntwo
RemoveEntry()
FindAlsoIns()
Gosub ResetLi
Break
ElseIf EventGadget() = Nodes()\li
If EventType() = #PB_EventType_RightClick
DisplayPopupMenu(Nodes()\ppm, WindowID(Nodes()\wnd))
EndIf
EndIf
Next
Case #PB_Event_Menu
Select EventMenu()
Case 001
ClipboardText$ = ""
For Index = 1 To ListSize(Nodes()\Entries()\alsoin$())
ClipboardText$ + Nodes()\Entries()\alsoin$()
Next
EndSelect
Case #PB_Event_SizeWindow
ForEach Nodes()
If Nodes()\wnd = EventWindow()
ResizeGadget(Nodes()\li, 0, 20, WindowWidth(Nodes()\wnd), WindowHeight(Nodes()\wnd) - 20)
SetGadgetItemAttribute(Nodes()\li, #False, #PB_ListIcon_ColumnWidth, GadgetWidth(Nodes()\li) - 140, 1)
ElseIf Nodes()\addwnd = EventWindow()
If IsGadget(Nodes()\addwndli)
ResizeGadget(Nodes()\addwndli, 20, 40, WindowWidth(Nodes()\addwnd) - 40, WindowHeight(Nodes()\addwnd) - 60)
EndIf
If IsGadget(Nodes()\addwndbntwo)
ResizeGadget(Nodes()\addwndbntwo, WindowWidth(Nodes()\addwnd) - 100, 10, 80, 20)
EndIf
EndIf
Next
EndSelect
ForEach Nodes()
Nodes()\S = GetWindowState(Nodes()\wnd)
If Nodes()\S = #PB_Window_Normal
Nodes()\X = WindowX(Nodes()\wnd)
Nodes()\Y = WindowY(Nodes()\wnd)
Nodes()\W = WindowWidth(Nodes()\wnd)
Nodes()\H = WindowHeight(Nodes()\wnd)
EndIf
Next
ForEver
;- XML-Datei schreiben
Xml = CreateXML(#PB_Any)
MainNode = CreateXMLNode(RootXMLNode(Xml))
SetXMLNodeName(MainNode, "Nodes")
ForEach Nodes()
Nodes()\Node = CreateXMLNode(MainNode)
SetXMLNodeName(Nodes()\Node, "Node")
SetXMLAttribute(Nodes()\Node, "X", Str(Nodes()\X))
SetXMLAttribute(Nodes()\Node, "Y", Str(Nodes()\Y))
SetXMLAttribute(Nodes()\Node, "W", Str(Nodes()\W))
SetXMLAttribute(Nodes()\Node, "H", Str(Nodes()\H))
SetXMLAttribute(Nodes()\Node, "S", Str(Nodes()\S))
SetXMLAttribute(Nodes()\Node, "Name", Nodes()\Name$)
ForEach Nodes()\Entries()
EntryNode = CreateXMLNode(Nodes()\Node)
SetXMLNodeName(EntryNode, "Entry")
SetXMLAttribute(EntryNode, "word", Nodes()\Entries()\word$)
Next
Next
SaveXML(Xml, GetHomeDirectory() + "standard.xml")
;-
End
ResetLi:
CurrentNode = ListIndex(Nodes())
ForEach Nodes()
ClearGadgetItems(Nodes()\li)
CurrentEntry = ListIndex(Nodes()\Entries())
ForEach Nodes()\Entries()
AlsoIn$ = ""
For Index = 1 To ListSize(Nodes()\Entries()\alsoin$())
SelectElement(Nodes()\Entries()\alsoin$(), Index - 1)
If AlsoIn$
AlsoIn$ + "; " + Nodes()\Entries()\alsoin$()
Else
AlsoIn$ + Nodes()\Entries()\alsoin$()
EndIf
Next
AddGadgetItem(Nodes()\li, #PB_Any, Nodes()\Entries()\word$ + Chr(10) + AlsoIn$)
Next
If Not CurrentEntry = #PB_Any
SelectElement(Nodes()\Entries(), CurrentEntry)
EndIf
Next
If Not CurrentNode = #PB_Any
SelectElement(Nodes(), CurrentNode)
EndIf
Return

Dabei habe ich den entsprechenden Button "Nodes()\addwndbntwo" gar nicht geklickt!
Eine Analyse der dynamisch verteilten Gadget-Nummern im Variablen-Viewer der PB-IDE ergab dann folgende Erkenntniss:

Wie ganz unten im Bild zu sehen ist hat "Nodes(:1:)\addwndli", das ListIconGadget im "Add Window" des zweiten Knoten, dieselbe Nummer wie "Nodes(:0:)\addwndbntwo", der Hinzufügen-Button im "AddWindow" des ersten Knotens.
Wie kann das sein?
/EDIT: Fehler gefunden. Eine dynamisch erzeugte Gadget-Nummer wird natürlich nur solange vorgehalten, wie der Gadget geöffnet ist. Da die "Add Windows" dynamisch erzeugt und auch gleich wieder geschlossen werden kann eine Doppelbelegung auftreten. Ich muss alle Add Windows im Vorraus erzeugen und dann nur noch dynamisch einblenden.
Sorry für diesen Thread.