Konfiguration von Xbase-Parts: Unterschied zwischen den Versionen
Georg (Diskussion | Beiträge) Keine Bearbeitungszusammenfassung |
Georg (Diskussion | Beiträge) (→:new()) |
||
Zeile 29: | Zeile 29: | ||
Einige der Konfigurationsparameter können über eigene Instanzvariablen oder Methoden eingestellt (oder geändert) werden, während andere nur über das Präsentations-Parameter Array festgelegt werden können. Spätere Änderungen sind dann über eine Änderung der Präsentations-Parameter und einen Aufruf der Methode :configure() möglich. | Einige der Konfigurationsparameter können über eigene Instanzvariablen oder Methoden eingestellt (oder geändert) werden, während andere nur über das Präsentations-Parameter Array festgelegt werden können. Spätere Änderungen sind dann über eine Änderung der Präsentations-Parameter und einen Aufruf der Methode :configure() möglich. | ||
==== Parameter ==== | |||
===== <Parent> ===== | |||
Der '''Parent''' ist das Objekt, in dessen Kontext das neue Objekt erstellt werden soll. Wird kein Parameter angegeben, ist das Objekt, das durch [[SetAppWindow()]] zurückgegeben wird, der Parent für das neue Objekt. | |||
Diese Beziehung kann durch die Methode [[:setParent()|setParent()]] abgefragt und auch verändert werden. | |||
=== :create() === | === :create() === |
Version vom 10. März 2014, 16:03 Uhr
Was sind Xbase-Parts
Xbase-Parts sind überwiegend von Windows-Controls abgeleitete graphische Elemente, die dazu verwendet werden, graphische Benutzerschnittstellen zu erstellen.
Die unterstützten Fenstertypen sind ebenfalls als Xbase-Parts definiert.
Alle Xbase-Parts, die im Zusammenhang mit der XbpBrowse()-Klasse stehen, sind nicht direkt von "echten" Windows-Controls abgeleitet.
Der Lebenszyklus eines Xbase-Parts
Der Lebenszyklus eines Xbase-Parts ist grundsätzlich durch drei Methoden gekennzeichnet:
- :new()
- :create()
- :destroy()
:new()
Jedes Xbase-Part "reagiert" auf die Methode :new() mit der Rückgabe einer Referenz auf ein neues Xbase-Part der eigenen Klasse:
oDlg := XbpDialog():new(<Parent>, <Owner>, >Position>, <Grösse>,; <Präsentations-Parameter>, <sichtbar>)
Im Anschluss kann das neue Xbase-Part konfiguriert werden, um den gewünschten Anforderungen zu genügen.
Einige der Konfigurationsparameter können über eigene Instanzvariablen oder Methoden eingestellt (oder geändert) werden, während andere nur über das Präsentations-Parameter Array festgelegt werden können. Spätere Änderungen sind dann über eine Änderung der Präsentations-Parameter und einen Aufruf der Methode :configure() möglich.
Parameter
<Parent>
Der Parent ist das Objekt, in dessen Kontext das neue Objekt erstellt werden soll. Wird kein Parameter angegeben, ist das Objekt, das durch SetAppWindow() zurückgegeben wird, der Parent für das neue Objekt.
Diese Beziehung kann durch die Methode setParent() abgefragt und auch verändert werden.
:create()
Wenn die Konfiguration abgeschlossen ist, wird das Xbase-Part "funktionsfähig" gemacht, indem Systemresourcen angefordert werden und (unter normalen Umständen) das Xbase-Part sichtbar gemacht wird.
Ab diesem Zeitpunkt können Änderungen an den Präsentations-Parametern nur über
oXbp:setPresParam(aPP) oXbp:configure()
geändert werden, d.h. das Xbase-Part muss explizit neu konfiguriert werden, damit die Änderungen auch wirksam werden.
:destroy()
Diese Methode wird wohl selten explizit ausgeführt. Sie wird jedoch rekursiv durchgeführt, wenn z.B. ein XbpDialog() mittels :destroy() zerstört wird. In diesem Fall wird bei allen abhängigen Xbase-Parts die Methode :destroy() ausgeführt, sofern sie nicht noch in einem anderen Kontext vorhanden sind (z.B. abweichender Owner).
Auswahl von Konfigurations-Variablen:
Falls verfügbar, zeigt diese Variable einen beschreibenden/ergänzenden Text am Xbase-Part an.
:tabStop
Diese Instanz-Variable legt fest, ob das Xbase-Part unter Verwendung der Tab-Taste angesprungen werden kann (Standard-Verhalten unter Windows). Entscheidend für die Reihenfolge, in der die Xbase-Parts angesprungen werden, ist die zeitliche Reihenfolge, in der :tabStop gesetzt wurde.
:cargo
Diese Instanz-Variable wird von Xbase++ nicht verwendet, sondern räumt dem Programmierer die Möglichkeit ein, bestimmte Information in einem Xbase-Part zu hinterlegen, ohne eine eigenen Klasse abzuleiten und darin weitere Felder zu definieren. Verwendung von :cargo auf eigene Gefahr.
Beispiele
Beispiel 1 - Auswahl aus einer Liste über einen modalen Dialog
Dialoge unter Windows sollten so gestaltet werden, dass sie nicht modal sind. Unter einem modalen Dialog versteht man eine Abfrage, die ein anderweitiges Arbeit mit dem Programm so lange blockiert, bis die Abfrage beantwortet wurde.
Das Beispiel fragt zu Programm-Start ab, welche SQL-Datenbank für den Programm-Lauf verwendet werden soll. Unterstellt wird die Verwendung der AppSys() aus dem AppSys.prg Artikel
#INCLUDE "Xbp.CH" Function Main() Local aPos, aSize, aList Local cTitle, cDataBase Local nI, nResult Local oDlg, oDlgWin, oXbp, oList // Schritt 1 - Definition der Auswahlliste aList := {"Produktion", "Test 1", "Test 2", "Remote Test"} // Schritt 2 - Erstellen des Dialogs aPos := {100, 100} aSize := {300, 300} cTitle := "Select Database For Operation" oDlgWin := XbpDialog():new(RootWindow():drawingArea,; RootWindow():drawingarea, aPos, aSize, NIL, .F.) oDlgWin:title := cTitle oDlgWin:create() // Schritt 3 - Bereitstellen einer Variablen für die :drawingArea oDlg := oDlgWin:drawingArea // Schritt 4 - Erzeugen einer XBpListbox() aPos := {10, 50} aSize := {260, 200} oList := XbpListBox():new(oDlg, oDlg, aPos, aSize) oList:tabStop := .T. oList:create() // Schritt 5 - Füllen der XbpListBox() mit den Daten der Auswahlliste FOR nI := 1 TO Len(aList) oList:addItem(aList[nI]) NEXT // Schritt 6 - Erstellen eines OK-Buttons aPos := {10, 10} aSize := {120, 30} oXbp := XbpPushButton():new(oDlg, oDlg, aPos, aSize) oXbp:tabStop := .T. oXbp:caption := "OK" oXbp:default := .T. oXbp:create() // Schritt 7 - Erstellen eines Cancel-Buttons aPos := {160, 10} oXbp := XbpPushButton():new(oDlg, oDlg, aPos, aSize) oXbp:tabStop := .T. oXbp:caption := "Cancel" oXbp:cancel := .T. oXbp:create() // Schritt 8 - Vorbereiten der Anzeige des XbpDialog() CenterControl(oDlgWin) // Schritt 9 - modale Anzeige des Dialogs nResult := oDlgWin:showModal() // Schritt 10 - verstecken und zerstören des Dialogs oDlgWin:hide() oDlgWin:destroy() // Schritt 11 - Abfrage der Auswahl IF nResult = XBP_MRESULT_OK cDatabase := oList:getItem(oList:getData()[1]) ELSE cDatabase := "" ENDIF ConfirmBox(, "Ausgewählt wurde Datenbank " + cDatabase, "Ergebnis",; XBPMB_OK, XBPMB_INFORMATION) RETURN(.T.)
Schritt 1 - Definition der Auswahlliste
Der Variablen aList wird für unser Beispiel eine Liste von zur Verfügung stehenden Datenbanken zugewiesen.
Schritt 2 - Erstellen des Dialogs
Hierzu werden Position und Grösse des Dialogs festgelegt, und der Variablen cTitle die Überschrift für den Dialog zugewiesen.
Anschliessend wird der Instanzvariablen :title der String zugewiesen, der in cTitle hinterlegt ist. Man kann alternativ die Zuweisung auch ohne den Umweg über cTitle machen.
Danach wird der Dialog erzeugt, indem Systemresourcen angefordert werden. Der Dialog selbst ist aber noch "unsichtbar".
Schritt 3 - Bereitstellen einer Variablen für die :drawingArea
Ein Fenster ist erst einmal ein rechtwinkliger Bereich. Ein XbpDialog() umfasst standardmässig (!) sowie die sogenannte Titlebar mit Systemmenü, Überschrift, sowie den Buttons zum Minimieren, Maximieren und Schliessen. Ebenfalls zur Grundausstattung gehört der Rahmen um einen solchen Dialog, und eventuell auch eine Menüleiste.
Der XbpDialog() besitzt einen als :drawingArea bezeichneten Bereich, der innerhalb (!) der gerade beschriebenen Elemente liegt und als "Zeichnungsfläche" für Xbase-Parts verwendet werden kann (soll).
Nach dieser Zuweisung sind oDlgWin:drawingArea und oDlg identisch, sie zeigen beide auf den gleichen Bereich. Die Verwendung der Variablen oDlg erlaubt es, mit weniger Schreibarbeit auszukommen.
Schritt 4 - Erzeugen einer XBpListbox()
Die XbpListBox() soll im oberen Bereich des Fensters angezeigt werden, entsprechend werden die Variablen aPos und aSize belegt. Da alle Elemente in diesem Dialog mit der Tab-Taste anspringbar sein sollen, muss bei jedem Xbase-Part die Instanzvariable :tabStop mit TRUE belegt werden.
Schritt 5 - Füllen der XbpListBox() mit den Daten der Auswahlliste
Erst nach dem Ausführen von :create() können nun Werte in die XbpListBox() eingetragen werden. Dies geschieht durch die Methode :addItem(). Die hinzugefügten Einträge werden in der Reihenfolge angezeigt, in der sie mittels :addItem() eingetragen wurden!
Schritt 6 - Erstellen eines OK-Buttons
Da wir mit einem modalen Dialog arbeiten wollen, gibt es bestimmte Bedingungen, die erfüllt werden müssen. Dazu gehört, dass es ein XbpPushButton()-Element geben muss, dessen Instanzvariable :default auf TRUE gesetzt sein muss (dies ist die Standard-Auswahl). Wie vorher bemerkt, soll der Anwender zwischen den Elementen mit der Tab-Taste springen können, daher wird auch hier :tabStop auf TRUE gesetzt. Als Caption wird "OK" vorgegeben.
Schritt 7 - Erstellen eines Cancel-Buttons
Um eine Auswahl zu bieten, muss auch ein Cancel-Button vorhanden sein. Analog zum OK- oder Default-Button gibt es auch hier eine Instanz-Variable, :cancel, die mit TRUE belegt sein muss, um dem XbpDialog() zu signalisieren, dass dieser XbpPushButton() zum Beenden des modalen Dialogs verwendet werden kann.
Schritt 8 - Vorbereiten der Anzeige des XbpDialog()
Mittels CenterControl(oDlgWin) wird der Dialog auf dem Bildschirm zentriert.
Schritt 9 - modale Anzeige des Dialogs
Die Methode :showModal() ist eine Neuerung, die einen Dialog ohne Event-Loop anzeigt. Der Event-Loop wird intern realisiert, und die Methode gibt zurück, ob OK oder Cancel ausgewählt wurde. Da wir hier gleichzeitig aber auch eine weitere Auswahl vornehmen wollen, müssen wir noch auf den Status von oList zugreifen:
Schritt 10 - verstecken und zerstören des Dialogs
Als erstes werden wir - in diesem Beispiel - den Dialog verstecken und zerstören. Wir haben ja noch eine Referenz auf die XbpListBox() in der Variablen oList.
Schritt 11 - Abfrage der Auswahl
Wenn der Dialog mit OK beendet wurde, lesen wir den ausgewählten Eintrag der XbpListBox() aus. Dies geschieht über die Methode :getData().
Ergebnis
Abbruch.
Der Zugriff auf oList funktioniert nicht so, wie man es erwarten würde. Obwohl ein Element ausgewählt und dann OK geklickt wurde, liefert
oList:getData()
ein leeres Array als Ergebnis zurück. Im Debugger bringt auch ein
oList:getItem(1)
als Ergebnis einen leeren String.
Mit der Anweisung oDlgWin:destroy() wurden auch alle abhängigen Xbase-Parts "zerstört". Dabei handelt es sich um
- XbpListBox
- XbpPushButton (OK)
- XbpPushButton (Cancel)
Da das XbpListBox-Element noch durch oList referenziert wird, wird die gesamte Kette eben nicht entsorgt, sondern oDlgWin, oDlg und oList bleiben "vorhanden", aber in einem Zustand, der "nicht gebrauchsfähig" ist.
Beispiel 1a - Auswahl aus einer Liste über einen modalen Dialog
Für dieses Beispiel ändern wir die Reihenfolge der letzten Anweisungen:
// Schritt 9 - modale Anzeige des Dialogs nResult := oDlgWin:showModal() // Schritt 10 - Abfrage der Auswahl IF nResult = XBP_MRESULT_OK cDatabase := oList:getItem(oList:getData()[1]) ELSE cDatabase := "" ENDIF ConfirmBox(, "Ausgewählt wurde Datenbank " + cDatabase, "Ergebnis",; XBPMB_OK, XBPMB_INFORMATION) // Schritt 11 - verstecken und zerstören des Dialogs oDlgWin:hide() oDlgWin:destroy()
Wenn das :destroy() nach der Abfrage ausgeführt wird, ist die Auswirkung auf unser Problem egal, da wir bereits die erforderliche Information abgefragt haben.
Beispiel 2 - Auswahl aus einer Liste über einen modalen Dialog mit mehr Komfort
Normalerweise erwartet ein Anwender, dass man (eventuell) durch einen Doppelklick auf den Eintrag in der ListBox diesen auswählen kann. Unser Dialog erlaubt das aber nicht, daher verwenden wir den Callback-Slot :itemSelected des XbpListBox() Objektes, um bei Auswahl (= Doppelklick) eine bestimmte Aktion ausführen zu lassen.
Function Main() Local aPos, aSize, aList Local cTitle, cDataBase Local nI, nResult Local oDlg, oDlgWin, oXbp, oList // Schritt 1 - Definition der Auswahlliste aList := {"Produktion", "Test 1", "Test 2", "Remote Test"} // Schritt 2 - Erstellen des Dialogs aPos := {100, 100} aSize := {300, 300} cTitle := "Select Database For Operation" oDlgWin := XbpDialog():new(RootWindow():drawingArea,; RootWindow():drawingarea, aPos, aSize, NIL, .F.) oDlgWin:title := cTitle oDlgWin:create() // Schritt 3 - Bereitstellen einer Variablen für die :drawingArea oDlg := oDlgWin:drawingArea // Schritt 4 - Erzeugen einer XBpListbox() aPos := {10, 50} aSize := {260, 200} oList := XbpListBox():new(oDlg, oDlg, aPos, aSize) oList:tabStop := .T. oList:create() // Schritt 5 - Füllen der XbpListBox() mit den Daten der Auswahlliste FOR nI := 1 TO Len(aList) oList:addItem(aList[nI]) NEXT // Schritt 6 - Erstellen eines OK-Buttons aPos := {10, 10} aSize := {120, 30} oXbp := XbpPushButton():new(oDlg, oDlg, aPos, aSize) oXbp:tabStop := .T. oXbp:caption := "OK" oXbp:default := .T. oXbp:create() // Schritt 6a - Verwendung von :itemSelected oList:itemSelected := {|| oXbp:activate(NIL, NIL, oXbp)} // Schritt 7 - Erstellen eines Cancel-Buttons aPos := {160, 10} oXbp := XbpPushButton():new(oDlg, oDlg, aPos, aSize) oXbp:tabStop := .T. oXbp:caption := "Cancel" oXbp:cancel := .T. oXbp:create() // Schritt 8 - Vorbereiten der Anzeige des XbpDialog() CenterControl(oDlgWin) // Schritt 9 - modale Anzeige des Dialogs nResult := oDlgWin:showModal() // Schritt 10 - Abfrage der Auswahl IF nResult = XBP_MRESULT_OK cDatabase := oList:getItem(oList:getData()[1]) ELSE cDatabase := "" ENDIF // Schritt 11 - verstecken und zerstören des Dialogs oDlgWin:hide() oDlgWin:destroy() ConfirmBox(, "Ausgewählt wurde Datenbank " + cDatabase, "Ergebnis",; XBPMB_OK, XBPMB_INFORMATION) RETURN(.T.)
Schritt 6a - Verwendung von :itemSelected
Wir legen fest, dass bei der Auswahl eines ListBox-Elements die :activate-Methode von oXbp ausgeführt werden soll.
Schritt 10 - Abfrage der Auswahl
Erstaunlicherweise erhalten wir jetzt immer XBP_MRESULT_CANCEL?
In dem Codeblock, den wir in Schritt 6a definiert haben, wird auf oXbp verwiesen. Zum Zeitpunkt der Codeblock-Definition (!) deutet oXbp auf den OK-Button. Danach wird oXbp verwendet, um den Cancel-Button zu erstellen. Darum verweist oXbp (auch im Codeblock) auf den Cancel-Button.
Wir benötigen also eine weitere Variable, um den Cancel-Button erstellen zu können:
LOCAL oXbpC ... aPos := {160, 10} oXbpC := XbpPushButton():new(oDlg, oDlg, aPos, aSize) oXbpC:tabStop := .T. oXbpC:caption := "Cancel" oXbpC:cancel := .T. oXbpC:create()
Und auf einmal funktioniert es, wie gewünscht:
Ein Doppelklick auf den gewünschten Eintrag in der ListBox löst automatisch auch einen virtuellen Klick auf den OK-Button aus.