Rückgabewerte von OpenWindow, CreateGadgetList und LoadFont

Anfängerfragen zum Programmieren mit PureBasic.
Salafat
Beiträge: 30
Registriert: 05.01.2012 07:40
Computerausstattung: AMD FX-8350 Eight-Core-Prozessor 4,00 GHz
8 GB RAM
Windows 7 64-Bit
Wohnort: Berlin

Rückgabewerte von OpenWindow, CreateGadgetList und LoadFont

Beitrag von Salafat »

Hallo,

ich habe früher kleinere Programme in PowerBasic geschrieben und bin nun zu PureBasic gewechselt, weil mir die IDE und insbesondere die Debugging-Fähigkeiten mehr gefallen. Die Unterschiede sind aber doch erheblich größer, als ich zunächst vermutet habe. Ich habe mich trotzdem unverdrossen ans Werk gemacht und versucht, mein erstes eigenes Fenster zu programmiert.

Hierbei stieß ich auf das Phänomen, daß PureBasic bei diversen Befehlen sog. Rückgabewerte erzeugt und ich nicht so richtig weiß, wozu. Konkrete Beispiele: Die Befehle OpenWindow, LoadFont und CreateGadgetList. Zu OpenWindow heißt es in der Hilfe:

"Öffnet ein neues Fenster entsprechend den übergegebenen Parametern." Soweit alles klar und selbstverständlich. Doch weiter heißt es: "Wenn #PB_Any als '#Window' Parameter verwendet wird, dann wird die Nummer des neuen Fensters als 'Ergebnis' zurückgegeben. Ist 'Ergebnis' gleich 0, konnte das Fenster nicht geöffnet werden." Ab diesem Punkt komme ich nicht mehr mit.

Wozu muß ein OpenWindow-Befehl überhaupt einen Rückgabewert erzeugen? Ich meine, wenn der Kode zur Fenstergenerierung fehlerhaft ist, dann kriegt man das ganz bestimmt mit, auch ohne daß man hierfür '0' als Rückgabewert nötig hätte. Das Fenster öffnet dann einfach nicht und man weiß, daß man etwas falsch gemacht hat (und muß sich dann den Kode eben noch einmal ansehen). Außerdem: Die Aussagekraft dieses zurückgegebenen Wertes '0' ist doch im wahrsten Sinne des Wortes gleich Null, weil dieser Rückgabewert ja kein Fehlerkode ist, der einem verriete, woran es denn gelegen hat, daß das Fenster nicht öffnet.

Was ich zu OpenWindow ausgeführt habe, gilt ebenso für CreateGadgetList. Denn mir ist aufgefallen, daß der eigentliche Fenster-Kode, der vom Visual Designer durch "Generate Source" erzeugt wird, in zwei If-Strukturen eingebunden ist:

Code: Alles auswählen

Procedure Open_Hf()
  If OpenWindow(#Hf, 460, 406, 281, 125, "Differenz",  #PB_Window_SystemMenu | #PB_Window_SizeGadget | #PB_Window_TitleBar )
    If CreateGadgetList(WindowID(#Hf))
      TextGadget(#Bz_Ztpkt_1, 7, 11, 71, 16, "Zeitpunkt 1:")
      SetgadgetFont(#Bz_Ztpkt_1, FontID1)
      StringGadget(#Tf_h1, 85, 8, 14, 22, "0", #PB_String_Numeric)
      TextGadget(#Bz_h1, 102, 11, 7, 18, "h")
      StringGadget(#Tf_min1, 115, 8, 21, 22, "00", #PB_String_Numeric)
      TextGadget(#Bz_min1, 139, 11, 22, 18, "min")
      StringGadget(#Tf_sek1, 164, 8, 21, 22, "00", #PB_String_Numeric)
      TextGadget(#Bz_sek1, 187, 11, 7, 18, "s")
      StringGadget(#Tf_tsek1, 198, 8, 27, 22, "000", #PB_String_Numeric)
      TextGadget(#Bz_tsek1, 228, 11, 42, 18, "/1000 s")
      TextGadget(#Bz_Ztpkt_2, 7, 40, 71, 16, "Zeitpunkt 2:")
      SetgadgetFont(#Bz_Ztpkt_2, FontID1)
      StringGadget(#Tf_h2, 85, 37, 14, 22, "0", #PB_String_Numeric)
      TextGadget(#Bz_h2, 102, 40, 7, 18, "h")
      StringGadget(#Tf_min2, 115, 37, 21, 22, "00", #PB_String_Numeric)
      TextGadget(#Bz_min2, 139, 40, 22, 18, "min")
      StringGadget(#Tf_sek2, 164, 37, 21, 22, "00", #PB_String_Numeric)
      TextGadget(#Bz_sek2, 187, 40, 7, 18, "s")
      StringGadget(#Tf_tsek2, 198, 37, 27, 22, "000", #PB_String_Numeric)
      TextGadget(#Bz_tsek2, 228, 40, 42, 18, "/1000 s")
      Frame3DGadget(#Ra_Erg, 10, 65, 149, 49, "Ergebnis")
      TextGadget(#Bz_Erg, 49, 87, 68, 16, "0,000 s", #PB_Text_Center)
      ButtonGadget(#Sf_Berechne, 172, 73, 98, 40, "Berechnen")
    EndIf
  EndIf
EndProcedure
Es ist mir völlig rätselhaft, welchem Zweck diese If-Abfragen dienen. Scheitern kann ja theoretisch jedes Beginnen auf dieser unvollkommenen Welt; wieso also nicht auch Rückgabewerte für Summen und Multiplikationen?

Nun zum Befehl FontLoad, der dem Format
Ergebnis = LoadFont(#Font, Name$, Höhe [, Flags])
folgt. Der Visual Designer erstellt vor der Fensterprozedur eine Zeile

Code: Alles auswählen

Global FontID1
FontID1 = LoadFont(1, "WH12G", 8)
um den Font "WH12G" als Standardzeichensatz für die Gadgets zu verwenden. Laut Hilfe gibt LoadFont einen "Wert ungleich Null zurück, wenn der Zeichensatz erfolgreich geladen wurde, und Null wenn nicht". Mit anderen Worten: In der globalen Variable FontID1 wird dann der Rückgabewert des Versuchs abgelegt, den Font "WH12G" zu laden; damit wäre FontID = 1, wenn der Versuch erfolgreich war, und 0 falls nicht. Aber was hat denn dieser Rückgabewert mit einer FontID zu tun? Eine unique Identifikationsnummer (was ja FontID1 doch wohl sein soll), ist doch nicht dasselbe wie ein Rückgabe-(Erfolgs-/Mißerfolgs-)Wert – schon allein deshalb nicht, weil dieser ja nur 0 und 1 zurückgeben kann, man aber doch mehr als 2 Fonts gleichzeitig laden können muß.

FontID1 wird dann in meinem Fensterkode oben zweimal verwendet: nämlich in beiden SetgadgetFont-Befehlen. Hier ist mir unklar, wieso zwei Setgadget-Befehle nötig sind. Denn der Zeichensatz ändert sich ja nicht, und ein Befehl zur Festlegung des Standard-Fonts für die Gadgets sollte doch genügen.

Vielen Dank
PureBasic v5.11 x64
Windows 7 64-Bit
AMD FX-8350 Eight-Core Processor 4 GHz, 8 GB Arbeitsspeicher
Benutzeravatar
RSBasic
Admin
Beiträge: 8047
Registriert: 05.10.2006 18:55
Wohnort: Gernsbach
Kontaktdaten:

Re: Rückgabewerte von OpenWindow, CreateGadgetList und LoadF

Beitrag von RSBasic »

Zuerst mal: Welche Version verwendest du? Falls 4.30 oder höher, dann ist "CreateGadgetList()" nicht mehr nötig, weil beim Erstellen eines neuen Fensters die GadgetListe automatisch erstellt wird. Deshalb brauchst du "CreateGadgetList()" nicht mehr.

Die If-Abfrage ist dazu da, um den Rückgabewert von OpenWindow abzufragen. Falls die Fenstererstellung fehlschlagen sollte, dann wird, wie du es bereits aus der Hilfe entnommen hast, Null zurückgegeben. Das Problem ist aber, dass die nachfolgenden Gadgets, die erstellt werden sollen, ebenfalls fehlschlagen. Daher ist es sinnvoll, dass du diesen Fehler abfängst, indem du eine If-Abfrage benutzt. D.h. die Gadgets werden also nur dann erstellt, wenn das Fenster erfolgreich erstellt wurde. Wenn nicht, dann soll er alles, was sich innerhalb des If-Wahr-Bereichs befindet, ignorieren bzw. überspringen. Beispielsweise kannst du am Ende vor "EndIf" ein "Else" schreiben und dazwischen beispielsweise "MessageRequester("", "Fehler beim Erstellen des Fensters.")" schreiben. Diese Fehlermeldung wird nur dann angezeigt, wenn das Fenster nicht erstellt werden konnte.
Ergo: Es ist einfach sauberer, wenn du die Fehler, die entstehen könnten, behandelst, um zu verhindern, dass andere Funktionen, die sich auf das Fenster beziehen, nicht ebenfalls fehlschlagen und eventuell weitere Fehler entstehen. Es könnte sein, dass deine Anwendung abstürzt und die Fehlersuche wäre für dich schwieriger.

Bei der Erstellung eines neuen Fensters kannst du die ID entweder statisch oder dynamisch definieren.
Statisch wäre etwa sowas:

Code: Alles auswählen

OpenWindow(1, ...
Nachteil ist, dass du die Nummer des Fensters merken müsstest, um auf dieses Fenster zuzugreifen. Beispielsweise um das Fenster zu verschieben. Du kannst das zwar die Fensternummer in einer Variable schreiben, aber dann könntest du gleich #PB-Any nehmen. #PB-Any wäre dann eine dynamische Nummerierung deines Fensters. Als Rückgabewert erhälst du irgendeine Fensternummer. Wie die Nummer lautet ist egal. Diese speicherst du einfach in einer Variable, die du dann für andere Zwecke nutzen kannst. Wie gesagt, beispielsweise um das Fenster zu verschieben.
Die letzte Möglichkeit wäre Enumeration für die ID-Nummerierung. Da können Konstanten (Variablen mit festen Werten) definiert werden, aber die Nummerierung wäre dann aufsteigend. (0, 1, 2, 3, ...)
Das kannst du etwa so machen:

Code: Alles auswählen

EnableExplicit

Define EventID

Enumeration
  #Window_Main
EndEnumeration

If OpenWindow(#Window_Main, 0, 0, 500, 400, "Window", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
  
  Repeat
    EventID = WaitWindowEvent()
    If EventID = #PB_Event_CloseWindow
      End
    EndIf
  ForEver
EndIf
Weitere Informationen findest du in der PB-Hilfe.
Aus privaten Gründen habe ich leider nicht mehr so viel Zeit wie früher. Bitte habt Verständnis dafür.
Bild
Bild
Salafat
Beiträge: 30
Registriert: 05.01.2012 07:40
Computerausstattung: AMD FX-8350 Eight-Core-Prozessor 4,00 GHz
8 GB RAM
Windows 7 64-Bit
Wohnort: Berlin

Re: Rückgabewerte von OpenWindow, CreateGadgetList und LoadF

Beitrag von Salafat »

Hallo RSBasic,

vielen Dank für Deine schnelle Antwort. Meine Version ist 4.60.
Die If-Abfrage ist dazu da, um den Rückgabewert von OpenWindow abzufragen. Falls die Fenstererstellung fehlschlagen sollte, dann wird, wie du es bereits aus der Hilfe entnommen hast, Null zurückgegeben. Das Problem ist aber, dass die nachfolgenden Gadgets, die erstellt werden sollen, ebenfalls fehlschlagen. Daher ist es sinnvoll, dass du diesen Fehler abfängst, indem du eine If-Abfrage benutzt. D.h. die Gadgets werden also nur dann erstellt, wenn das Fenster erfolgreich erstellt wurde.
So in etwa habe ich mir das schon gedacht -- als eine von vornherein eingebaute Fehlerbehandlungsroutine, die man z.B. in VBA extra programmieren muß. Nur: Warum um alles in der Welt sollte denn ein vom Visual Designer generierter OpenWindow-Befehl überhaupt fehlschlagen? Dieser "vorauseilende Pessimismus" von PureBasic scheint mir einfach übertrieben. Und selbst gesetzt den Fall, man tippt selbst und kommt mit den Parametern von OpenWindow durcheinander: Was ist so schlimm daran, wenn dann wie in VisualBasic die OpenWindow-Zeile rot markiert wird und eine Fehlermeldung erscheint? Beim Ersttest des Programms dürften wohl 90% der Programmierer ihren Kode sowieso im Einzelschrittmodus abarbeiten, und dann verwirrt eine solche Zuweisung wie Ergebnis = OpenWindow... mehr, als daß sie nützt.

Du schreibst ferner, daß ab v4.30 CreateGadgetList() nicht mehr nötig sei. Ich verstehe das so, daß ich

Code: Alles auswählen

OpenWindow(#Hf, 460, 406, 281, 125, "Differenz",  #PB_Window_SystemMenu | #PB_Window_SizeGadget | #PB_Window_TitleBar )
  TextGadget(#Bz_Ztpkt_1, 7, 11, 71, 16, "Zeitpunkt 1:")
  SetGadgetFont(#Bz_Ztpkt_1, FontID1)
  ...
schreiben kann, d.h. nach dem OpenWindow-Befehl gleich die Gadgets folgen lassen kann. Woher weiß aber PureBasic dann, auf welches Fenster sich die Gadget-Befehle beziehen? In TextGadget(...) z.B. wird die Fensternummer #Hf nirgendwo genannt (aber in CreateGadgetList() wird sie genannt).

Könntest Du mir bitte noch erklären, wieso der Rückgabewert von LoadFont (s. meinen Quelltext) plötzlich als ID in einem SetgadgetFont-Befehl figuriert? Der gesamte Quelltext wurde, wie gesagt, vom Visual Designer erstellt, und ich kann mir keinen Reim darauf machen.

Vielen Dank
PureBasic v5.11 x64
Windows 7 64-Bit
AMD FX-8350 Eight-Core Processor 4 GHz, 8 GB Arbeitsspeicher
Benutzeravatar
STARGÅTE
Kommando SG1
Beiträge: 7031
Registriert: 01.11.2005 13:34
Wohnort: Glienicke
Kontaktdaten:

Re: Rückgabewerte von OpenWindow, CreateGadgetList und LoadF

Beitrag von STARGÅTE »

OpenWindow() baut vermutlich auf die CreateWindowEX_() API auf, und die gibt nun mal auch Null zurück, wenn das Erstellen nicht funktioniert hat.

Sicher ist das in manchen Augen "kleinkram" da der Fall vermutlich nie eintritt.
Aber aus genau diesem Grund kann es auch mal irgendwann dazu kommen, dass man einen Fehler bekommt, und nicht weiß woher er kommt.
____

Sobald ein neues Fenster geöffnet ist, ist dies autoamtisch die neue Gadget-List.
Möchtest du woanders Gadgets hinzufügen musst du UseGadgetList(WindowID) nutzen.
____

Der Rückgabewert von PB-Funktionen hat unterschiedliche Bedeutungen, jenachdem was du für einen Parameter angibst.
Am Beispiel von LoadFont():
  • Gibst du bei LoadFont als Nummer die #PB_Any Konstante an, so wird dir die dynamisch generierte Nummer der Font zurückgegeben. Um hier an das Systemhandle zu kommen, wäre noch FontID(Nummer) nötig.
  • Gibst du bei LoadFont als Nummer eine Konstante oder Zahl an, so wird dir die dazugehörige Systemspezifische ID zurückgegeben. Dieser Rückgabewert entsprecht also FontID(Nummer)
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Aktuelles Projekt: Lizard - Skriptsprache für symbolische Berechnungen und mehr
Benutzeravatar
TheCube
Beiträge: 169
Registriert: 20.07.2010 23:59
Computerausstattung: Risen 3400G 16MB Win10-64Bit
Wohnort: NRW

Re: Rückgabewerte von OpenWindow, CreateGadgetList und LoadF

Beitrag von TheCube »

...warum sollte denn ein vom Visual Designer generierter OpenWindow-Befehl überhaupt fehlschlagen?
Na wenn auch auf deinem Programmiersystem alles super läuft, du eine EXE generierst und dann später auf deinem anderen Zielsystem kein Speicher zum Öffnen eines weiteren Fensters zur Verfügung steht. (unwahrscheinlich, aber möglich ... :freak: )
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8809
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: Rückgabewerte von OpenWindow, CreateGadgetList und LoadF

Beitrag von NicTheQuick »

Wenn du 'LoadFont(1, "WH12G", 8)' nutzt, ist es nicht wichtig den Rückgabewert zu speichern, da du ja schon festgelegt hast welche ID für den Font benutzt werden soll, nämlich 1. Hättest du allerdings 'LoadFont(#PB_Any, "WH12G", 8)' genutzt, müsstest du den Rückgabewert speichern, damit du ihn später für die restlichen Font-Befehle nutzen kannst.

Jetzt zu 'OpenWindow()'. Natürlich ist es sehr unwahrscheinlich, dass der OpenWindow-Befehl fehlschlägt. Und wie du selbst sagst, sollten einem falsche Parameter schon auffallen, bevor man das Programm irgendwie weiter gibt oder produktiv benutzen will. Aber es gibt noch andere Befehle als 'OpenWindow', die häufiger fehlschlagen können. Z.B. das WebGadget. Es ist nicht auf jedem System gewährleistet, dass dessen Erstellung auf jeden Fall funktioniert. Vielleicht hat ja ein Anwender deiner Software irgendwelche Libraries nicht installiert oder ähnliches. Dann musst du natürlich den Rückgabewert abfangen und eine entsprechende Fehlermeldung ausgeben, bevor das ganze Programm einfach nur mit einem Ausnahmefehler abstürzt.

Im Übrigen ist der VisualDesigner leider schon sehr veraltet, hat viele Fehler, und sollte gerade in den neueren PB-Versionen nicht mehr genutzt werden. Das ist aktuell ein Manko und ich weiß nicht, wann sich das wieder ändern wird. Das hat jedenfalls schon einige hier gestört, dass dieser Teil von PB nicht mehr aktiv weiterentwickelt wird.
Salafat
Beiträge: 30
Registriert: 05.01.2012 07:40
Computerausstattung: AMD FX-8350 Eight-Core-Prozessor 4,00 GHz
8 GB RAM
Windows 7 64-Bit
Wohnort: Berlin

Re: Rückgabewerte von OpenWindow, CreateGadgetList und LoadF

Beitrag von Salafat »

Danke für die Antworten. Gut, mit dem Rückgabewert ist es halt wie es ist, und es ist ja auch kein Problem (nur eben halt anders als in VB oder PowerBasic). Eine Frage (bzw. einen Verdacht) habe ich noch: Könnte es sein, daß der OpenWindow-Befehl gar nicht "1" als Wert zurückgibt, wenn die Erstellung des Fensters gelingt, sondern eine andere Zahl?

Und: Wann genau braucht man das "echte" (Windows-)Handle für das Fenster, und wann die mehr oder weniger selbstgewählte Fenster-Nummer?

Vielen Dank
PureBasic v5.11 x64
Windows 7 64-Bit
AMD FX-8350 Eight-Core Processor 4 GHz, 8 GB Arbeitsspeicher
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8809
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: Rückgabewerte von OpenWindow, CreateGadgetList und LoadF

Beitrag von NicTheQuick »

Wenn du 'OpenWindow(#FesteID, ...)' nutzt, dann ist der Rückgabewert meines Wissens das Handle des Fensters, genau wie es die entsprechende WinAPI-Funktion zurückgibt (Windows und Mac analog). Du erhälst dann also die selbe Zahl als Rückgabewert wie du durch 'WindowID(#FesteID')' erhalten würdest. Nutzt du allerdings 'OpenWindow(#PB_Any, ...)', erhälst du als Rückgabewert eine dynamische ID, die aber von PB verwaltet wird. Das heißt hier kommst du NUR mittels 'WindowID(Rückgabewert)' an das Handle wie es das Betriebssystem nutzt.

Nur in wenigen Fällen brauchst du dieses Handle, das du mittels 'WindowID()' und analogen Befehlen erhalten kannst. Die meisten PB-Funktionen nutzen auch die internen PB-IDs. Wenn es mal anders ist, wird das auch in der Hilfe erwähnt. Und dann ist es normalerweise auch aus einem guten Grund genau so.

ich nehme an die PB-internen IDs wurden wegen der Plattformunabhängigkeit eingeführt. Und vielleicht auch deswegen, weil es nur so die Möglichkeit gibt feste, also konstante Werte, als IDs zu nutzen.
Salafat
Beiträge: 30
Registriert: 05.01.2012 07:40
Computerausstattung: AMD FX-8350 Eight-Core-Prozessor 4,00 GHz
8 GB RAM
Windows 7 64-Bit
Wohnort: Berlin

Re: Rückgabewerte von OpenWindow, CreateGadgetList und LoadF

Beitrag von Salafat »

Danke, NicTheQuick, das war sehr hilfreich. Die Antworten der anderen natürlich auch.

PS. Gibt es einen Grund, warum Du mich darauf hinweist, daß die deutsche Rechtschreibung nicht Open Source ist? Ich ignoriere in der Tat die sog. Rechtschreibreform, glaube ansonsten aber weitgehend korrekt zu schreiben.
PureBasic v5.11 x64
Windows 7 64-Bit
AMD FX-8350 Eight-Core Processor 4 GHz, 8 GB Arbeitsspeicher
Benutzeravatar
STARGÅTE
Kommando SG1
Beiträge: 7031
Registriert: 01.11.2005 13:34
Wohnort: Glienicke
Kontaktdaten:

Re: Rückgabewerte von OpenWindow, CreateGadgetList und LoadF

Beitrag von STARGÅTE »

Das gehört zu seiner Signatur, wird also an jedem seiner Beiträge angehängt.
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Aktuelles Projekt: Lizard - Skriptsprache für symbolische Berechnungen und mehr
Antworten