Einsteiger-Kapitel - Dynamische Nummerierung von Fenstern und Gadgets mittels #PB_Any
Wenn Sie in die Hilfe-Artikel des OpenWindow Befehls oder eines der Befehle zur Gadget-Erstellung (zum Beispiel ButtonGadget()) geschaut haben, oder mit dem Form-Designer experimentiert haben, werden Sie Verweise auf eine spezielle Konstante genannt #PB_Any bemerkt haben. In diesem Artikel schauen wir uns diese etwas näher an, um herauszufinden, warum diese so bedeutsam ist.Im Enumerations Abschnitt beachten Sie, dass es nur Aufzählungen für die Menü-Einträge gibt. Diese werden auf allen Fenstern gemeinsam genutzt - obwohl jedes Fenster seine eigene Menüleiste hat.Zum Schluss bleibt anzumerken, dass eine Map nicht den einzigen Weg darstellt, diesen Effekt zu erreichen. Eine verknüpfte Liste oder ein Array kann für diesen Job ebenfalls verwendet werden, wenn Sie möchten - auch wenn der Code für das Implementieren dieser Alternativen wegen der Unterschiede wie diese arbeiten etwas anders gegenüber dem hier präsentierten aussehen muss.
Im Structures Abschnitt beachten Sie, dass die POLYGONWINDOW Struktur vier Integer-Werte beinhaltet und somit einen Platz bietet, die Verweise auf die Menüleiste, einen Text, eine Auswahlbox und einen Zeichenbereich zu speichern.
Im Variablen-Abschnitt beachten Sie, dass in Ergänzung zu den üblichen Variablen zum Empfangen von Ereignis-Details eine Map namens ActiveWindows mittels der zuvor definierten POLYGONWINDOW Struktur erstellt wird.
Schauen Sie auf die CreatePolygonWindow Prozedur.
Wenn wir das Fenster erstellen, speichern wir das Ergebnis der @openwindowFunktion in einer Variable genannt ThisWindow. Dann konvertieren wir diese in einen String-Wert und verwenden diesen als Schlüssel für einen neuen Map-Eintrag.
Wenn wir dann das Menü und die Text-, Combobox- und Image-Gadgets auf dem neuen Fenster erstellen, werden die von diesen Funktionen zurückgegebenen Referenzen ebenfalls in der Map gespeichert.
Werfen Sie dann einen Blick auf die ResizePolygonWindow Prozedur.
Beachten Sie, wie der Wert von EventWindow von der Ereignis-Schleife in diese Prozedur übergeben wird. Dieser Wert wird dann verwendet, um Referenzen auf die untergeordneten Steuerelemente aus der Map zu erhalten, und diese Referenzen werden dann verwendet, um die Gadgets in der Größe zu verändern.
Schauen Sie auf die DestroyPolygonWindow Prozedur.
Hier werden die Referenzen auf die untergeordneten Steuerelemente aus der Map entfernt, wenn ein Fenster geschlossen wird. Wenn die Größe der Map Null erreicht - gibt es keine weiteren offenen Fenster und DestroyPolygonWindow setzt ein Ereignis-Flag, was dem Programm mitteilt, dass es beendet werden kann.
Starten Sie nun das Programm.
- Verwenden Sie den 'New Window' Menüeintrag, um zwei oder drei neue Polygon-Fenster zu öffnen.
- Verwenden Sie die Combobox in jedem Fenster, um ein unterschiedliches Aussehen auszuwählen – beachten Sie, dass jedes Fenster unabhängig von allen anderen arbeitet.
- Verändern Sie einige der Fenster in der Größe – beachten Sie, dass sie alle unabhängig von einander in der Größe verändert werden können und sich auch das Polygon mit dem Fenster in der Größe anpasst.
; Compiler Direktiven EnableExplicit ; Konstanten CompilerIf Defined(Blue, #PB_Constant) = #False #Blue = 16711680 #Gray = 8421504 #White = 16777215 CompilerEndIf ;- Enumerations ; Die Menü-Befehle werden bei allen Fenstern die gleichen sein. Enumeration #MenuNew #MenuClose EndEnumeration ;- Structures ; Diese Struktur wird alle Referenzen auf die einmaligen Elemente eines Fensters beinhalten. Structure POLYGONWINDOW Menu.i LabelSides.i ComboSides.i ImagePlot.i EndStructure ;- Variablen ; Diese Map verwendet die zuvor definierte Struktur, um die Referenzen auf alle geöffneten Fenster festzuhalten. NewMap ActiveWindows.POLYGONWINDOW() ; Ereignis-Variablen. Define.i Event, EventWindow, EventGadget, EventType, EventMenu, EventQuit Define.s EventWindowKey ; Implementierung. Procedure.i CreatePolygonWindow() ; Erstellt ein neues Fenster und Gadgets, fügt dieses und seine untergeordneten Gadgets zur Tracking-Map hinzu. Shared ActiveWindows() Protected.i ThisWindow Protected.s ThisKey ThisWindow = OpenWindow(#PB_Any, 50, 50, 300, 300, "Polygon", #PB_Window_SystemMenu | #PB_Window_SizeGadget | #PB_Window_MinimizeGadget | #PB_Window_TitleBar) WindowBounds(ThisWindow, 250, 250, #PB_Ignore, #PB_Ignore) If ThisWindow ; Maps erhalten einen String-Wert als Schlüssel, weshalb wir die Integer-Zahl 'ThisWindow' in einen String umwandeln. ThisKey = StrU(ThisWindow) ; Ein Map-Element hinzufügen, um alle neuen Gadget-Referenzen festzuhalten. AddMapElement(ActiveWindows(), ThisKey) ; Erstelle die Menüleiste. ActiveWindows(ThisKey)\Menu = CreateMenu(#PB_Any, WindowID(ThisWindow)) MenuTitle("Window") MenuItem(#MenuNew, "New Window") MenuItem(#MenuClose, "Close Window") ; Erstelle die untergeordneten Gadgets und speichere ihre Referenzen in der Map. With ActiveWindows() ; Ein Beschriftungstext für die Auswahlbox. \LabelSides = TextGadget(#PB_Any, 5, 5, 150, 20, "Number of Sides:") ; Die Auswahlbox. \ComboSides = ComboBoxGadget(#PB_Any, 160, 5, 100, 25) AddGadgetItem(\ComboSides, 0, "Triangle") AddGadgetItem(\ComboSides, 1, "Diamond") AddGadgetItem(\ComboSides, 2, "Pentagon") AddGadgetItem(\ComboSides, 3, "Hexagon") AddGadgetItem(\ComboSides, 4, "Heptagon") AddGadgetItem(\ComboSides, 5, "Octagon") AddGadgetItem(\ComboSides, 6, "Nonagon") AddGadgetItem(\ComboSides, 7, "Decagon") ; Dreieck auswählen. SetGadgetState(\ComboSides, 0) ; Das sichtbare Image-Gadget auf dem Fenster. \ImagePlot = ImageGadget(#PB_Any, 5, 35, 290, 240, 0, #PB_Image_Border) EndWith EndIf ; Gibt die Referenz auf das neue Fenster zurück. ProcedureReturn ThisWindow EndProcedure Procedure DestroyPolygonWindow(Window.i) ; Entfernt das Fenster 'Window' aus der 'ActiveWindows' Map, schließt das Fenster und setzt das Quit Flag, wenn nötig. Shared EventQuit, ActiveWindows() Protected.s ThisKey ; Konvertiert den Integer-Wert 'Window' in einen String. ThisKey = StrU(Window) ; Löscht den Map-Eintrag. DeleteMapElement(ActiveWindows(), ThisKey) ; Schließt das Fenster. CloseWindow(Window) ; Überprüft, ob es noch offene Fenster gibt. If MapSize(ActiveWindows()) = 0 EventQuit = #True EndIf EndProcedure Procedure.i ResizePolygonWindow(Window.i) ; Verändert die untergeordneten Gadgets auf dem Fenster in ihrer Größe. ; In der Praxis muss bei diesem Beispiel nur das ImageGadget in der Größe verändert werden. Shared ActiveWindows() Protected.i ThisImage Protected.i X, Y, W, H Protected.s ThisKey ; Ermittelt Referenzen auf die betroffenen Gadgets aus der Map. ThisKey = StrU(Window) ThisImage = ActiveWindows(ThisKey)\ImagePlot ; Verändert die Gadgets in der Größe. W = WindowWidth(Window) - 15 H = WindowHeight(Window) - 70 ResizeGadget(ThisImage, #PB_Ignore, #PB_Ignore, W, H) EndProcedure Procedure PlotPolygon(Window.i) ; Zeichnet das Polygon-Bild und überträgt es auf das Image-Gadget. Shared ActiveWindows() Protected.f Radius, OriginX, OriginY, StartX, StartY, EndX, EndY Protected.i Sides, Vertex, Width, Height, ThisCombo, ThisImage, ThisPlot Protected.s ThisKey ; Überprüft, ob das Ereignis für das richtige Fenster ist. If Not IsWindow(Window) : ProcedureReturn : EndIf ; Ermittelt Referenzen auf die betroffenen Gadgets aus der Map. ThisKey = StrU(Window) ThisCombo = ActiveWindows(ThisKey)\ComboSides ThisImage = ActiveWindows(ThisKey)\ImagePlot ; Berechnet Abmessungen und Herkunft. Sides = GetGadgetState(ThisCombo) + 3 Width = GadgetWidth(ThisImage) - 4 Height = GadgetHeight(ThisImage) - 4 OriginX = Width/2 OriginY = Height/2 If Width < Height Radius = OriginX - 50 Else Radius = OriginY - 50 EndIf ; Erstellt ein neues Bild. ThisPlot = CreateImage(#PB_Any, Width, Height) StartDrawing(ImageOutput(ThisPlot)) ; Zeichnet einen weißen Hintergrund. Box(0, 0, Width, Height, #White) ; Zeichnet einen grauen umlaufenden Kreis. Circle(OriginX, OriginY, Radius, #Gray) ; Zeichnet das Polygon. For Vertex = 0 To Sides ; Berechnet den Startpunkt. StartX = OriginX + (Radius * Cos(2 * #PI * Vertex/Sides)) StartY = OriginY + (Radius * Sin(2 * #PI * Vertex/Sides)) ; und den Endpunkt. EndX = OriginX + (Radius * Cos(2 * #PI * (Vertex + 1)/Sides)) EndY = OriginY + (Radius * Sin(2 * #PI * (Vertex + 1)/Sides)) ; Zeichnet die Seite in blau. LineXY(StartX, StartY, EndX, EndY, #Blue) Next Vertex ; Füllt das Polygon in blau. FillArea(OriginX, OriginY, #Blue, #Blue) StopDrawing() ; Übertragt den Bild-Inhalt in das sichtbare Gadget. SetGadgetState(ThisImage, ImageID(ThisPlot)) ; Löscht das temporäre Bild. FreeImage(ThisPlot) EndProcedure ;- Hauptteil ; Erstellt das erste Fenster. EventWindow = CreatePolygonWindow() ResizePolygonWindow(EventWindow) PlotPolygon(EventWindow) ;- Ereignis-Schleife Repeat Event = WaitWindowEvent() EventWindow = EventWindow() EventWindowKey = StrU(EventWindow) EventGadget = EventGadget() EventType = EventType() EventMenu = EventMenu() Select Event Case #PB_Event_Gadget ; Ein Gadget-Ereignis ist aufgetreten. If EventGadget = ActiveWindows(EventWindowKey)\LabelSides ; Tue nichts. ElseIf EventGadget = ActiveWindows(EventWindowKey)\ComboSides ; Wenn sich die Auswahlbox verändert hat, das Bild neu zeichnen. PlotPolygon(EventWindow) ; Aktualisiert den Fenstertitel, um das neue Aussehen wiederzuspiegeln. SetWindowTitle(EventWindow, GetGadgetText(ActiveWindows(EventWindowKey)\ComboSides)) ElseIf EventGadget = ActiveWindows(EventWindowKey)\ImagePlot ; Tue nichts. EndIf Case #PB_Event_Menu ; Ein Menü-Ereignis ist aufgetreten. If EventMenu = #MenuNew EventWindow = CreatePolygonWindow() ResizePolygonWindow(EventWindow) PlotPolygon(EventWindow) ElseIf EventMenu = #MenuClose DestroyPolygonWindow(EventWindow) EndIf Case #PB_Event_Repaint ; Ein Fenster-Inhalt wurde für ungültig erklärt. PlotPolygon(EventWindow) Case #PB_Event_SizeWindow ; Ein Fenster wurde in der Größe verändert. ResizePolygonWindow(EventWindow) PlotPolygon(EventWindow) Case #PB_Event_CloseWindow ; Ein Fenster wurde geschlossen. DestroyPolygonWindow(EventWindow) EndSelect Until EventQuit = #True
Einsteiger-Kapitel Navigation
< Vorheriges: Speicher-Zugriff | Überblick | Nächstes: Verwalten mehrerer Fenster >