Erstellen von Menüs in Visual FoxPro
Rodney Hill
Wenn Sie Windows95-kompatible Anwendungen entwickeln, wollen Sie diesen auch ein
Menüsystem zuordnen, das dem Anwender die Funktionalitäten der Anwendung zur Verfügung
stellt. Das Entwicklerhandbuch von Visual FoxPro behandelt die Mechanismen, mit denen Sie
das Menüsystem erstellen und ist daher ein guter Startpunkt für die Entwicklung. Dieser
Artikel fügt noch Informationen für folgende Bereiche hinzu:
- Ihren Anwendungen Menüs hinzufügen
- Den Menüs, die mit dem Menüdesigner erstellt wurden, dynamische Elemente hinzufügen
- Top-Level-Formularen Menüs zuordnen
- Erstellen von Menüklassen
- Datengesteuerte Menüs erstellen
Die meisten Informationen treffen sowohl auf Visual FoxPro 3.0 als auch auf die Version
5.0 zu. Wenn sich Informationen nur auf VFP 5.0 beziehen, wird das jeweils explizit
angemerkt.
Ihrer Anwendung Menüs hinzufügen
Der schnellste und einfachste Weg für die Erstellung eines Menüs führt über den
Menü-Designer. Ich nehme in diesem Artikel daher auch an, daß Sie diesen Weg wählen.
Der beste Ansatz bei dieser Arbeit ist wahrscheinlich der, den Microsoft auch beim
Internet nimmt: "zu eigen machen und erweitern". Auf den Menü-Designer bezogen
heißt das, daß Sie die Werkzeuge, die uns Visual FoxPro zur Verfügung stellt, benutzen
und deren Fähigkeiten durch das Hinzufügen eigenen Codes erweitern.
Das Entwickeln von Menüs mit dem Menü-Designer ist im Entwicklerhandbuch von VFP
beschrieben. Grundsätzlich läuft der Prozeß folgendermaßen ab:
- Sie erstellen mit Hilfe des Menü-Designers die Struktur des Menüs und ordnen den
einzelnen Menüeinträgen die Befehle zu, die ausgeführt werden, wenn der Anwender den
Eintrag auswählt.
- Sie generieren das Visual FoxPro-Menü (eine Programmdatei mit der Erweiterung .MPR).
- Sie führen das Programm in Ihrer Anwendung aus, um das Menü zu erstellen.
Wird ein Menüprogramm ausgeführt, macht es nichts anderes als jedes andere
VFP-Programm auch: Es führt seine Aufgabe aus (in diesem Fall die Definition und die
Anzeige des Menüs) und beendet sich anschließend. Das Menüprogramm bleibt nicht im
Hintergrund aktiv, um auf eine Menüauswahl des Anwenders zu warten. Die Befehle, die nach
der Auswahl eines Menüpunkts ausgeführt werden, sind systemweit verfügbar. Das
bedeutet, daß sie Zugriff auf alle globalen Variablen (und globale Objektreferenzen)
sowie auf alle die Prozeduren/Funktionen haben, deren Programmdateien mit dem Befehl SET
PROCEDURE TO... bekanntgemacht wurden.
Da Sie außerhalb des Codes einer Methode die Befehle THIS oder THISFORM nicht
einsetzen können, dürfen Sie diese auch nicht im Code, der nach einer Menüauswahl
ausgeführt wird, benutzen. Um aus einem Menü heraus Methoden aufzurufen oder
Eigenschaften eines Formulars zu verändern, verwenden Sie die Objektreferenz des Objekts,
oder allgemeiner _SCREEN.ActiveForm. Im Eintrag "Beenden" des Datei-Menüs
könnten Sie beispielsweise die folgende Codezeile verwenden:
=_SCREEN.ActiveForm.Release()
Erstellen modularer Menüs
Sie können im Menü-Designer Ihre gesamte Menüstruktur Ihrer Anwendung erstellen und
daraus ein einziges Menü generieren. Allerdings ist das nicht das optimale Vorgehen. Auch
im Menü können Sie von den gleichen Vorzügen profitieren, die Sie auch bei der
modularen oder objektorientierten Programmierung genießen, indem Sie modulare Menüs
entwerfen.
Statt für Ihre gesamte Anwendung ein Gesamtmenü zu aufzubauen, erstellen Sie separate
Programme für jedes Menü oder für einzelne Menügruppen Ihres Systems. Wenn Sie
beispielsweise getrennte Menüs für Datei, Bearbeiten, Fenster, Hilfe und Ihre
anwendungsspezifischen Einträge erstellen, können Sie diese in allen Ihren Anwendungen
einsetzen; der Code steht aber an einer zentralen Stelle. Bei Bedarf können Sie spezielle
Menüs hinzufügen oder auch löschen.
Die Erstellung einzelner Menüs im Menü-Designer ist ein einfacher und gerader Weg,
modulare Menüs zu erzeugen. Es gibt aber auch andere Werkzeuge und Techniken für diese
Aufgabe. So hat beispielsweise Andrew Ross MacNeill das Public Domain-Werkzeug GenMenuX
geschrieben, mit dem Sie wiederverwendbare Vorlagen für modulare Menüs erstellen
können. Sie können sich GenMenuX von verschiedenen Internetseiten sowie aus dem
FOXUSER-Forum und natürlich auch aus dem dFPUG-Forum in Compuserve herunterladen.
Speichern und Wiederherstellen des Original-Menüs
Bedenken Sie in Ihrer Anwendung, daß Sie das bestehende Menü sichern, bevor Sie Ihr
eigenes Menüprogramm ausführen und es, nachdem Sie Ihre Anwendung beendet haben, auch
wiederherstellen. Als Beispiel ein Auszug aus dem Hauptprogramm einer Anwendung:
* Push the existing menu on the menu stack
PUSH MENU _MSYSMENU
* Display interface
DO File.MPR
DO Edit.MPR
DO MyApp.MPR
DO Window.MPR
DO Help.MPR
DO FORM InitialForm
* Allow interface to process events
READ EVENTS
* Restore the original menu
POP MENU _MSYSMENU
Der Menü-Stack arbeitet wie alle Stacks nach dem Prinzip last in, first out. Wenn Sie
Menü A auf den Stack packen, Menü B ausführen, anschließend Menü B dem Stack
hinzufügen, um Menü C auszuführen und anschließend den Befehl POP MENU aufrufen, wird
Menü B wiederhergestellt. Ein weiterer Aufruf von POP MENU aktiviert dann Menü A.
PUSH MENU _MSYSMENU belegt circa 12 Kilobyte Hauptspeicher, ein vollständiges
benutzerdefiniertes Menü eventuell sogar noch erheblich mehr. Sie sollten möglichst für
jedes Menü, das Sie auf den Stack packen, ein anderes Menü daraus entfernen, um den
Speicherbedarf so niedrig wie möglich zu halten.
Die Verwendung von Untermenüs
Untermenüs sind Menüs, die geöffnet werden, wenn der Anwender einen Eintrag in einem
anderen Menü auswählt. Sie können die Untermenüs zwar auch mit dem Menü-Designer
einfach erstellen; es muß aber nicht unbedingt sein. Untermenüs erfordern mehr
Mausaktionen durch den Anwender und zeigen nicht die Zusammenhänge und visuelle
Benutzerführung wie es eine Dialogbox kann. Anwender akzeptieren selten ein Untermenü
mit nur einem Eintrag. Diesen Eintrag könnte der Entwickler auch einfach dem
Originalmenü hinzufügen. Wenn Untermenüs unvermeidbar sein sollten, dann sollten Sie
sich bemühen, mit einem Shortcut ein Untermenü öffnen zu lassen. Auf keinen Fall sollte
man die Menüs zu tief verschachteln.
Dynamische Elemente in Menüs, die mit dem Menü-Designer erstellt wurden, integrieren
Mit den Menü-Befehlen und -Funktionen von VFP können Sie zusammen mit dem Menü- und
dem Formular-Designer dynamische Menüs erstellen, die zur Laufzeit konfigurierbar sind.
Die Elemente des Menüs
Der Menü-Designer generiert (mit _GENMENU) die Menüdefinition. Wenn Sie diesen
Menücode verstehen, sind Sie auch in der Lage, die Menüs, die Sie mit dem Menü-Designer
erstellt haben, zu erweitern.
Die Terminologie ist bei den Menüs grundsätzlich, und besonders bei FoxPro, immer ein
Problem. Die Dokumentation von Microsoft benutzt beispielsweise die Begriffe Menübefehl,
Menüoption und Menüpunkt synonym, wenn es um die programmatische Erstellung eines
Menüeintrags mit dem Befehl DEFINE BAR geht. Im Code von Visual FoxPro besteht ein Menü
aus PADs in _MSYSMENU, es werden POPUPs aktiviert, wenn ein Anwender ein PAD auswählt und
die BARs sind die Einträge, die der Anwender wählt, um eine Aktion ausführen zu lassen.
Wenn sich dieser Artikel (und auch die VFP-Dokumentation) auf Menüs bezieht, sind ein
PAD, ein POPUP oder ein oder mehrere BARs gemeint.
|
Die folgende Abbildung zeigt, wie VFPs Menüdefinition und die Menüelemente
zusammengehören.
|
Suchen Sie einmal in der Hilfe von Visual FoxPro nach "Menüs und
Menüeinträge". Sie erhalten eine Liste aller Menüdefinitionen und Befehle, die
sich auf die Menüs beziehen, zusammen mit Querverweisen auf die exakte Syntax und auf
Beispiele. Das folgende Beispiel betrachtet die wichtigsten Menübefehle in der
Reihenfolge, in der sie normalerweise ausgeführt werden.
Bevor Sie das Menüsystem Ihrer Anwendung aufbauen, müssen Sie das Systemmenü von
Visual FoxPro löschen. Die folgende Codezeile löscht alle Einträge aus dem Systemmenü.
SET SYSMENU TO
Jetzt können Sie dem Systemmenü einen neuen Eintrag hinzufügen, indem Sie den Befehl
DEFINE PAD benutzen.
DEFINE PAD
padReports OF _MSYSMENU ;
PROMPT \<Berichte ;
MESSAGE
Welcher Bericht soll ausgeführt werden?
Wenn nun ein Anwender auf den neuen Eintrag klickt, passiert nichts. Sie müssen ein
Popup mit Bars darauf definieren, um ein Menü anzuzeigen, wie der Anwender es erwartet,
wenn er auf ein Menü klickt.
DEFINE
POPUP popReports MARGIN
ON PAD
padReports OF _MSYSMENU ACTIVATE POPUP popReports
DEFINE BAR
1 OF popReports ;
PROMPT Rechnung
|
MESSAGE "Drucken einer Rechnung"
|
Wenn der Anwender jetzt auf den Eintrag klickt, wird ihm der Eintrag
"Rechnungen" angezeigt. Das nutzt aber auch noch nicht viel; Sie müssen dem
Eintrag erst noch Code hinzufügen, der angibt, welche Aktion mit dem Menüpunkt
verknüpft werden soll.
ON SELECTION BAR 1 OF popReports REPORT FORM INVOICE.FRX PREVIEW
Benutzen der Systemmenüs von Visual FoxPro
Zusätzlich zu den selbstentwickelten Menüs können Sie auch vordefinierte Menüpunkte
von Visual FoxPro in Ihrer Anwendung einsetzen. Es gibt auch einige gute Gründe, weshalb
Sie das tun sollten.
- Bei den Systemmenüs ist die Funktionalität bereits eingebaut. Das Menü
"Bearbeiten" (Padname MSMEDIT, Popupname _MEDIT) beispielsweise ermöglicht das
Ausschneiden, Kopieren, Einfügen und Suchen von Text. Wenn Sie Ihrem Anwender dieses
Menü nicht zur Verfügung stellen, kann er diese Aktionen nicht ausführen. Das Menü
"Fenster" (Padname MSMWINDO, Popupname _MWINDOW) zeigt die Namen der aktuell
ausgeführten Formulare an und ermöglicht es dem Anwender, diese Formulare zu aktivieren.
- Unter dem Menüpunkt Ansicht - Allgemeine Optionen des Menüdesigners können Sie eine
Position vor oder nach einem Systemmenü-Pad wählen.
Um sich alle Systemmenüs und Menüeinträge anzeigen zu lassen, suchen Sie in der
Hilfe von VFP nach "Systemmenünamen" oder benutzen Sie SYS(2013). Die Option
"Standardmenü" fügt Ihrem Menü alle Systemmenüs hinzu. Anschließend können
Sie Ihr Menü anpassen. Wenn Sie in VFP 5.0 eine generische Menükomponente einfügen
wollen, können Sie im Menü-Designer "Leiste einfügen..." wählen und
anschließend eine einzelne Menüoption aus der Liste auswählen.
Falls Sie ein anwendungsspezifisches Menü entwickeln, möchten Sie eventuell die
Systemmenüs von Visual FoxPro nicht einsetzen. Sie müssen aber trotzdem die Plazierung
des Menüs im Dialog "Allgemeine Optionen" angeben. Wenn Sie Ihr
anwendungsspezifisches Menü links vom Fenster-Menü anzeigen wollen, wählen Sie
zunächst in den Allgemeinen Optionen "Vor" und anschließend in der nun
erscheinenden Combo-Box "Fenster" aus.
Sie können auf die Funktionalität der VFP-Systemmenüs programmatisch mit der
Funktion SYS(1500) zugreifen. Wenn beispielsweise das aktive Fenster ein Eingabeformular
ist, öffnet die folgende Codezeile den "Suchen"-Dialog von Visual FoxPro:
?SYS(1500, "_MED_FIND", "_MEDIT")
Deaktivieren einzelner Menüpunkte
Einer der häufigsten Gründe, ein Menü der aktuellen Arbeitsumgebung des Anwenders
anzupassen, ist die Aktivierung und Deaktivierung einzelner Menüpunkte. Wenn Sie einen
Menüeintrag definieren, können Sie die SKIP-Klausel benutzen, um festzulegen, wann ein
Menüpunkt deaktiviert werden soll. Falls der Ausdruck feststellt, daß der Befehl SKIP
FOR .T. zurückgibt, wird der Menüeintrag deaktiviert. Wenn beispielsweise das Menü
"Datei" den Eintrag "Schließen" zum Beenden der aktiven Maske
enthält, stellt der folgende Code sicher, daß der Eintrag nur dann aktiviert wird und
damit genutz werden kann, wenn auch ein Formular aktiv ist:
DEFINE BAR
3 OF _MFILE ;
PROMPT Close ;
MESSAGE Close the currently active form ;
SKIP FOR TYPE("_SCREEN.ActiveForm") != "O"
ON
SELECTION BAR 3 OF _MFILE _SCREEN.ActiveForm.Release
In der Beispielsanwendung Solutions, die mit Visual FoxPro ausgeliefert wird, finden
Sie zwei Beispiele, die das Deaktivieren von Menüeinträgen demonstrieren:
"Koordinieren von Menüleisten und Symbolleistenschaltflächen" und
"Entfernen/Anzeigen von Häkchen neben Menübefehl". Wenn Sie diese Beispiele
ausführen, können Sie sich mit der F1-Taste anzeigen lassen, wie diese Beispiele
implementiert wurden.
Die Systemmenüs von VFP stellen automatisch sicher, daß die jeweils passenden Punkte
deaktiviert werden. So werden beispielsweise die Einträge "Ausschneiden",
"Kopieren" und "Einfügen" des Menüs "Bearbeiten" (Padname
MSMEDIT, Popupname _MEDIT) automatisch deaktiviert, wenn kein Text markiert ist bzw. sich
kein Text in der Zwischenablage befindet.
Wenn Sie einen Menüeintrag erstellen, können Sie die SKIP FOR-Klausel im
Menü-Designer eingeben. Da Sie sowohl die Klausel SKIP FOR als auch den Befehl SET SKIP
OF einsetzen können, um ein Menüpopup oder das gesamte Menü durch die Deaktivierung des
Eintrags in der Menüleiste zu deaktivieren, handelt es sich hier nicht um eine
Standardschnittstelle für Windows-Anwendungen. Ist ein Menü nicht auf eine gegebene
Umgebung anwendbar, so muß es insgesamt gelöscht werden. Dies wird im folgenden
Abschnitt beschrieben.
Menüeinträge mit Formularen verbinden
Häufig wollen Sie die Funktionalität eines Formulars erweitern, indem Sie selten
genutzte Funktionalitäten im Menü bereitstellen. Das Menü ist nur verfügbar, solange
das Formular aktiv ist. Daher müssen Sie, sobald das Formular deaktiviert wird, das Menü
löschen. Ist beispielsweise VFPs Projekt-Manager das aktive Fenster, finden Sie in der
Menüleiste das Menü "Projekt". Ist der Projekt-Manager nicht das aktive
Fenster, wird das Menü gelöscht.
Wie verbinden Sie ein Menü mit einem Formular?
- Erstellen Sie im Menü-Designer ein Menü mit den zu dem Formular gehörenden
Einträgen.
- Wenn der Menü-Designer aktiv ist, wählen Sie im Menü "Ansicht" den Eintrag
"Allgemeine Optionen..."
- Wählen Sie "Anfügen", "Vor" oder "Nach", um die
Positionierung des Menüs festzulegen. Wählen Sie nicht "Ersetzen", da Sie
sonst alle anderen Einträge der Menüleiste verlieren, wenn Ihr Formular ausgeführt
wird.
- Klicken Sie im Menü-Designer auf die Schaltfläche "Optionen", um den Dialog
"Optionen zur Bezeichnung" zu öffnen.
- Definieren Sie hier einen Tastentext, den Sie benötigen, wenn Sie den Eintrag aus der
Menüleiste löschen.
- Generieren Sie den Menücode.
Das Menü mit dem Formular verbinden:
- Im Ereignis Activate des Formulars rufen Sie Ihr Menü auf. Befindet es sich
beispielsweise in FORMMENU.MPR, benötigen Sie dafür folgenden Code:
- DO FormMenu.MPR
- In den Ereignissen Deactivate und Destroy des Formulars geben Sie das Menü wieder
frei. Wenn Sie Ihr Menü myform genannt haben, schreiben Sie in beide Ereignisse:
RELEASE PAD myform OF _MSYSMENU
Anzeigen der zuletzt benutzten Dokumente im Menü Datei
Windowsanwendungen zeigen im Menü Datei häufig eine Liste der zuletzt genutzten (MRU
= most recently used) Dokumente an, so daß der Anwender schnell wieder zu einem Dokument
zurückkehren kann, das er bearbeitet. Es ist relativ einfach, diese Funktionalität auch
in eigene Anwendungen zu integrieren.
Speichern der zuletzt genutzten Dokumente
Um die zuletzt benutzten Formulare, Berichte oder Abfragen im Menü Datei anzuzeigen,
müssen Sie Informationen über diese Dokumente in einer Tabelle speichern. Die folgende
Tabelle speichert, welcher Eintrag im Menü angezeigt werden soll, die Aktion, die
ausgeführt werden soll, wenn der Anwender den Eintrag auswählt, und den Zeitpunkt der
letzten Nutzung der Dokumente.
Wahrscheinlich haben Sie nicht vor, die letzten dreißig Formulare, Berichte oder
Abfragen im Dateimenü anzuzeigen. Sie müssen daher die Anzahl der anzuzeigenden
Einträge beschränken. Vier bis acht Einträge sind sinnvoll.
Wenn der Anwender nun eine Abfrage, einen Bericht oder ein Formular ausführt, ändern
Sie die Informationen in dieser Tabelle, in diesem Beispiel UPREFS.DBF, entsprechend ab.
Dies wird im folgenden Code demonstriert.
In diesem Code ist cFormName der Name des Formulars, das der Anwender ausführt,
cAction ist eine Zeichenkette, die anzeigt, welche Aktion ausgeführt werden soll, wenn
der Anwender den Menüeintrag auswählt, um das Formular erneut zu öffnen, und nMaxItems
gibt die höchstmögliche Anzahl an Einträgen an, die Sie festgelegt haben.
SELECT
Uprefs
LOCATE FOR
prompt = cFormName
IF FOUND()
REPLACE Timestamp WITH DATETIME()
ELSE
IF RECCOUNT() < nMaxItems && maximal anzuzeigende Einträge
INSERT INTO Uprefs VALUES(cFormName, cAction, DATETIME())
ELSE
SET ORDER TO Timestamp ASCENDING && der älteste zuerst
GO TOP
REPLACE prompt WITH cFormName
REPLACE Action WITH cAction
REPLACE Timestamp WITH DATETIME()
ENDIF
ENDIF
Sie müssen nach jeder Änderung der Tabelle das Menüprogramm erneut aufrufen:
DO FILE.MPR
Die MRU-Dokumente dem Dateimenü hinzufügen
Wenn Sie im Menü-Designer das Menü Datei erstellen, legen Sie alle Einträge in das
Menü fest mit Ausnahme des Separators und dem Eintrag Beenden am Ende des Menüs. Diese
werden, sobald die MRU-Dokumente eingetragen sind, programmatisch hinzugefügt.
Fügen Sie den folgenden Code Ihrer Abschlußprozedur hinzu. In diesem Code gibt die
Variable nBar immer die Anzahl der definierten Einträge im Menü wieder. Die Variable
iPrefix enthält die Ziffer, die neben dem Dokument angezeigt wird.
nBar =
CNTBAR("_MFILE")
cOldAlias =
ALIAS()
IF
!USED('UPrefs')
USE UPrefs IN 0
ENDIF
SELECT
Uprefs
* Sortieren, um
sicherzustellen, daß das zuletzt benutzte Dokument am Anfang steht
SET ORDER
TO timestamp DESCENDING
IF
RECCOUNT() > 0 && es sind Dokumente gespeichert
iPrefix = 0
nBar = nBar
+ 1
* Vor der
MRU-Liste einen Separator anzeigen
DEFINE BAR nBar OF _MFILE PROMPT "\-"
SCAN
nBar = nBar + 1
iPrefix = iPrefix + 1
cAction = ALLTRIM(UPrefs.Action)
DEFINE BAR nBar OF _MFILE PROMPT "\<" + ;
ALLTRIM(STR(iPrefix)) + " " + UPrefs.Prompt
ON SELECTION BAR nBar OF _MFILE &cAction
ENDSCAN
ENDIF
* Den Eintrag
Beenden hinzufügen
DEFINE BAR
nBar + 1 OF _MFILE PROMPT "\-"
DEFINE BAR
nBar + 2 OF _MFILE PROMPT "\<Beenden"
ON
SELECTION BAR nBar + 2 OF _MFILE CLEAR EVENTS
IF
!EMPTY(cOldAlias)
SELECT (cOldAlias)
ENDIF
Ausgehend von den zwei Einträgen in unserem Beispiel zeigt die folgende Abbildung das
daraus resultierende Menü.
Top-Level-Formularen Menüs hinzufügen
Ein Top-Level-Formular (auch Single Document Interface oder SDI-Formular genannt) wird
nicht vom Hauptfenster von Visual FoxPro abgeleitet. Sie erstellen ein Top-Level-Formular
in Visual FoxPro 3.0, indem Sie die Eigenschaft Desktop des Formulars auf .T. setzen.
Top-level-Masken sind aber erst in Visual FoxPro 5.0 wirklich eigenständige Fenster mit
einem eigenen Eintrag in der Windows-Taskbar. In VFP 5.0 erstellen Sie ein
Top-Level-Formular, indem Sie die Eigenschaft ShowWindow des Formulars auf "2 - As
Top-Level Form" setzen. Da das Top-Level-Formular nicht im Hauptfenster von VFP
enthalten ist und daher nicht notwendigerweise Zugriff auf das Systemmenü hat, könnten
Sie den Wunsch hegen, dem Formular ein Menü direkt hinzuzufügen.
Der Menü-Designer von VFP 3.0 erlaubt es Ihnen nicht, ein Menü für ein
Top-Level-Formular zu erstellen. Sie müssen daher den Code selbst schreiben. Der folgende
Code kann dem Ereignis Init eines Formulars hinzugefügt werden, um ihm ein Menü
hinzuzufügen:
DEFINE
MENU _example BAR IN WINDOW (THISFORM.Name) COLOR SCHEME 1
DEFINE PAD
p1 OF _example PROMPT "\<Datei"
DEFINE PAD
p2 OF _example PROMPT "\<Farbe"
ON PAD p1
OF _example ACTIVATE POPUP file
ON PAD p2
OF _example ACTIVATE POPUP color
DEFINE
POPUP file MARGIN
DEFINE BAR
1 OF file PROMPT "\<Beenden"
ON
SELECTION BAR 1 OF file _SCREEN.ActiveForm.Release
DEFINE
POPUP color MARGIN
DEFINE BAR
1 OF color PROMPT "Vordergrund"
DEFINE BAR
2 OF color PROMPT "Hintergrund"
ON
SELECTION BAR 1 OF color _SCREEN.ActiveForm.SetAll("ForeColor", GETCOLOR())
ON
SELECTION BAR 2 OF color _SCREEN.ActiveForm.SetAll("BackColor", GETCOLOR())
ACTIVATE
MENU _example NOWAIT
In Visual FoxPro 5.0 können Sie die Menüs der Top-Level-Formulare mit dem
Menü-Designer erstellen. Rufen Sie dafür im Menü Ansicht den Dialog "Allgemeine
Optionen" auf und klicken dann auf "Formular der obersten Ebene."
Wenn Sie das Menü für ein Top-Level-Formular generieren, enthält der generierte Code
Kommentare darüber, wie das Menü zu verwenden ist:
@@@* To
attach this menu to your Top-Level form,
* call it
from the Init event of the form:
* Syntax:
DO <mprname> WITH <oFormRef> [,<cMenuname>|<lRename>]
*
oFormRef - form object reference (THIS)
*
cMenuname - name for menu
*
lRename - renames Name property of your form
* example:
*
PROCEDURE Init
*
DO mymenu.mpr WITH THIS,.T.
*
ENDPROC
* Use the
optional 2nd parameter if you plan on running
* multiple
instances of your Top-Level form. The logical
* lRename
parameter will change the name property of your
* form to
the same name given the menu and may cause conflicts
* in your
code if you directly reference the form by name.
* You will
also need to remove the menu when the form is
*
destroyed so that it does not remain around in memory
* unless
you wish to reactivate it later in a new form.
* If you
passed the optional lRename parameter as .T. as in
* the
above example, you can easily remove the menu in the
* form's
Destroy event as shown below. This strategy is ideal
* when
using multiple instances of Top-Level forms.
* example:
*
PROCEDURE Destroy
*
RELEASE MENU (THIS.Name)
*
ENDPROC
Erstellen von Shortcut-Menüs
Ein Shortcut-Menü, auch Kontextmenü genannt, wird angezeigt, wenn der Anwender mit
der rechten Taste auf ein Objekt klickt. Wenn Sie in Visual 5.0 ein neues Menü erstellen,
haben Sie die Auswahl, ob Sie ein normales oder ein Shortcut-Menü erstellen möchten.
In der Anwendung Solutions von VFP 5.0 sind zwei Beispiele für Shortcut-Menüs
enthalten: "Anzeigen von Shortcut-Menüs" und "Erstellen dynamischer
Kontextmenüs". Das Beispiel "Erstellen dynamischer Kontextmenüs", das im
Abschnitt "Erstellen von Shortcut-Menüs ohne den Menü-Designer" näher
beschrieben wird, benutzt die Codedefinition einer Hilfsklasse für Menüs, um das
Shortcut-Menü zu erstellen. Mit kleinen Anpassungen kann der Code auch in VFP 3.0
verwendet werden.
Anzeigen von Markierungszeichen neben den Einträgen der Shortcut-Menüs
Sie können neben den Einträgen der Shortcut-Menüs dynamisch Markierungszeichen (Sie
wissen schon: diese kleinen Häkchen) anzeigen lassen, indem Sie im Initialisierungscode
des Menüs die Direktive #PREPOP und im Abschlußcode den Befehl SET MARK OF einsetzen.
Die Präprozessoranweisung #PREPOP legt fest, daß der Abschlußcode des Menüs vor dem
Befehl ACTIVATE POPUP generiert wird.
Das Beispiel "Anzeigen von Shortcut-Menüs" aus Solution zeigt Ihnen, wie Sie
die Markierungszeichen in einem Kontextmenü implementieren können.
Die folgende Codezeile gehört zum Ereignis RightClick des Beispielsformulars von
"Anzeigen von Shortcut-Menüs":
DO frmshort.mpr WITH THIS
FRMSHORT ist das Kontextmenü. Der folgende Code stammt aus dem Initialisierungscode
des Menüs:
PARAMETER oREF
#PREPOP
Der Parameter oREF ermöglicht es Ihnen, Eigenschaften eines Objekts (in diesem Fall
des Formulars) im Code des Menüs auszulesen und zu schreiben. Der folgende Code aus dem
Abschlußcode setzt ein Markierungszeichen neben einem Menüeintrag, wenn die Eigenschaft
AlwaysOnTop des Formulars auf .T. gesetzt ist.
SET MARK OF BAR 4 OF frmshort TO oRef.AlwaysOnTop
Der Code des Menüs enthält die folgenden Zeilen, die die Anzeige des Menüeintrags
ändern wenn das Kontextmenü angezeigt wird:
SET MARK OF BAR 4 OF frmshort TO oRef.AlwaysOnTop
ACTIVATE POPUP frmshort
Ohne die Anweisung #PREPOP würde folgender Code generiert:
ACTIVATE POPUP frmshort
SET MARK OF BAR 4 OF frmshort TO oRef.AlwaysOnTop
Da die Ausführung des Codes durch den Befehl ACTIVATE POPUP unterbrochen wird, bis der
Anwender seine Auswahl getroffen hat, wird der Befehl SET MARK OF erst ausgeführt, wenn
das Shortcut-Menü nicht mehr angezeigt wird, was nicht unbedingt sonderlich sinnvoll ist.
Erstellen von Shortcut-Menüs ohne den Menü-Designer
Sie können Shortcut-Menüs auch ohne den Menü-Designer erstellen. Das Beispiel
"Erstellen dynamischer Kontextmenüs" demonstriert die Entwicklung eines
Kontextmenüs, das durch ein Array gesteuert wird. Da das Menü durch die Daten gesteuert
wird, ist es zur Laufzeit leichter zu konfigurieren. Das Vorgehen läuft sowohl in VFP 3.0
als auch unter 5.0.
Um den folgenden Code in Visual FoxPro 3.0 auszuführen, müssen Sie allerdings das
Schlüsselwort SHORTCUT aus dem Befehl DEFINE POPUP löschen. SHORTCUT wurde in Visual
FoxPro 5.0 neu eingeführt, um das Standardverhalten von Windows 95 bei Kontextmenüs
bereitzustellen.
Das Ereignis RightClick des Beispiels enthält den folgenden Code. Das Objekt
oMenuShortcut, das in diesem Beispiel referenziert wird, basiert auf VFPs Klasse menulib,
die Sie in der Klassenbibliothek \SAMPLES\CLASSES\UTILITY.VCX finden.
LOCAL
laMenu[5]
laMenu=""
laMenu[1]="\<Zentrieren"
laMenu[2]="\<Font..."
laMenu[3]="\<Minimieren"
laMenu[4]="\-"
laMenu[5]="\<Beenden"
THISFORM.oMenuShortcut.ShowMenu(@laMenu)
DO CASE
CASE BAR()=1
THISFORM.AutoCenter=.T.
CASE BAR()=2
THISFORM.SetFont && eine benutzerdefinierte Methode
CASE BAR()=3
THISFORM.WindowState=1
CASE BAR()=5
THISFORM.Release
ENDCASE
Die Methode ShowMenu() des Objekts oMenuShortCut (das auf der Klasse menulib basiert)
enthält den folgenden Code:
LPARAMETERS
taMenu,tcOnSelection
LOCAL
lcOnSelection,lnMenuCount,lnCount,llDoubleArray
LOCAL
lcMenuItem,lcMenuSelection
EXTERNAL
ARRAY taMenu
IF
PARAMETERS()=0 OR TYPE("taMenu")#"C"
RETURN .F.
ENDIF
lnMenuCount=0
lnMenuCount=ALEN(taMenu,1)
IF
lnMenuCount=0
RETURN .F.
ENDIF
llDoubleArray=(ALEN(taMenu,2)>0)
ACTIVATE
SCREEN
DEACTIVATE
POPUP _popShortcutMenu
DEFINE
POPUP _popShortcutMenu ;
FROM MROW(),MCOL() ;
MARGIN ;
RELATIVE ;
SHORTCUT
FOR lnCount
= 1 TO lnMenuCount
lcMenuItem=IIF(llDoubleArray,taMenu[lnCount,1],taMenu[lnCount])
DEFINE BAR lnCount OF _popShortcutMenu PROMPT (lcMenuItem)
ENDFOR
ON
SELECTION POPUP _popShortcutMenu DEACTIVATE POPUP _popShortcutMenu
ACTIVATE
POPUP _popShortcutMenu
RELEASE
POPUP _popShortcutMenu
IF BAR()=0
RETURN .F.
ENDIF
IF
llDoubleArray
lcMenuSelection=taMenu[BAR(),2]
IF NOT EMPTY(lcMenuSelection) AND TYPE("lcMenuSelection")=="C"
lcOnSelection=ALLTRIM(lcMenuSelection)
ENDIF
IF EMPTY(lcOnSelection)
lcOnSelection=ALLTRIM(IIF(EMPTY(tcOnSelection),"",tcOnSelection))
ENDIF
ELSE
lcOnSelection=ALLTRIM(IIF(EMPTY(tcOnSelection),"",tcOnSelection))
ENDIF
IF
EMPTY(lcOnSelection)
RETURN .F.
ENDIF
&lcOnSelection
Wenn der Anwender mit der rechten Maustaste auf das Formular klickt, wird das
Shortcut-Menü durch das Array definiert und angezeigt.
Erstellen von Menüklassen
Menüs sind in Visual FoxPro keine Objekte. Sie können aber um die Menüdefinition
herum Wrapper-Klassen schreiben, um auch dort bei den Menüs über die vertraute
Objektschnittstelle zu verfügen. Es gibt unterschiedliche Implementierungen für
Menüklassen. Im Codebook von Yair Alan Griver (Sybex-Verlag, 1995) finden Sie den Code
und die Dokumentation für eine stabile Menüklasse. Weitere Menüklassen können Sie sich
aus dem Internet herunterladen. Hier ein sehr einfaches Beispiel für die Erstellung und
Benutzung von Menüklassen:
PUSH MENU
_MSYSMENU
bar1 =
CREATEOBJECT("mBar", "Test1", "bar1",
"MESSAGEBOX(PROMPT())")
bar2 =
CREATEOBJECT("mBar", "Test2", "bar2",
"MESSAGEBOX(PROMPT())")
bar3 =
CREATEOBJECT("mBar", "Done", "bar3", "POP MENU
_MSYSMENU")
pop1 =
CREATEOBJECT("mPop", "pop1")
pop1.AddBar(bar1)
pop1.AddBar(bar2)
pop1.AddBar(bar3)
pad1 =
CREATEOBJECT("mPad", "Pad1", "No message")
pad1.SetPopup(pop1)
* Class
Definitions
DEFINE
CLASS mpad AS CUSTOM
PadName = ""
Message = ""
PROCEDURE Init(cName, cMessage)
THIS.PadName = cName
THIS.Message = cMessage
DEFINE PAD (cName) OF _MSYSMENU ;
PROMPT cName MESSAGE cMessage
ENDPROC
PROCEDURE SetPopup(oPopup)
cName = THIS.PadName
cPopup = oPopup.PopName
ON PAD (cName) OF _MSYSMENU ACTIVATE POPUP (cPopup)
ENDPROC
ENDDEFINE
DEFINE
CLASS mpop AS CUSTOM
PopName = ""
BarCount = 0
PROCEDURE Init(cName)
THIS.PopName = cName
DEFINE POPUP (cName) MARGIN
ENDPROC
PROCEDURE AddBar(oBar)
cName = THIS.PopName
cAction = oBar.Action
THIS.BarCount = THIS.BarCount + 1
DEFINE BAR THIS.BarCount OF (cName) ;
PROMPT oBar.Prompt ;
MESSAGE oBar.Message
ON SELECTION BAR THIS.BarCount OF (cName) &cAction
ENDPROC
ENDDEFINE
DEFINE
CLASS mBar AS CUSTOM
Prompt = ""
Message = ""
Action = ""
PROCEDURE Init(cPrompt, cMessage, cAction)
THIS.Prompt = cPrompt
THIS.Message = cMessage
THIS.Action = cAction
ENDPROC
ENDDEFINE
Erstellen datengesteuerter Menüs
Datengesteuerte Menüs sind flexibler und zur Laufzeit besser zu konfigurieren. Sie
können Ihre eigenen Prozeduren oder Klassen erstellen, die das Lesen von Daten aus einer
oder aus mehreren Tabellen verwalten. Anschließend wird aus den Daten, die in der Tabelle
gespeichert sind, das Menü erstellt. Das folgende Beispiel zeigt das Design eines
vollständig durch Daten gesteuerten Menüsystems.
Dieses Beispiel arbeitet mit einer Tabelle, die Systeminformationen für das Menü
enthält. Zusätzlich gibt es eine getrennte Tabelle für jedes Popup. Die Tabelle mit den
Systeminformationen heißt Menubar und wird hier definiert:
CREATE
TABLE MENUBAR ;
(NPAD C(15), ;
PROMPT C(25), ;
MESSAGE M,
;
POPNAME
C(15), ;
DBFNAME
C(10))
Mögliche Werte für einige Datensätze in der Tabelle:
NPAD |
PROMPT |
MESSAGE |
POPNAME |
DBFNAME |
_MSM_FILE |
\>Datei |
Öffnen, Schließen, Speichern usw. |
_MFILE |
FILE |
_MSM_EDIT |
\>Bearbeiten |
Kopieren, Ausschneiden, Einfügen usw. |
_MEDIT |
EDIT |
Dieses Beispiel benötigt eine getrennte Tabelle für jedes Menü, die alle
Menüeinträge und die Informationen enthält, welche Aktion ausgeführt wird, wenn der
Eintrag ausgewählt wird. Sie könnten beispielsweise eine Tabelle mit der folgenden
Struktur benutzen:
CREATE
TABLE FILE ;
(NBAR C(15), ;
PROMPT C(25), ;
MESSAGE M, ;
SKIPFOR M, ;
HOTKEY C(8), ;
ACTION M)
Einige mögliche Datensätze in der Tabelle File:
NBAR |
PROMPT |
MESSAGE |
SKIPFOR |
HOTKEY |
ACTION |
|
|
|
R |
Y |
|
1 |
\>Neu |
Neuer Kunde |
|
Ctrl+N |
DO NewCustomer |
2 |
Ö\>ffnen |
Formular öffnen |
|
Ctrl+F |
DO FORM
GETFILE('scx') |
Wenn Sie die Daten eingetragen haben, können Sie ein Programm oder eine Methode
aufrufen, um die Daten auslesen und das Menü aufbauen zu lassen. Der folgende Code
arbeitet sich durch die Tabelle Menubar und erstellt auf der Grundlage dieser Daten die
Menüs.
SELECT
MenuBar
SCAN
DEFINE PAD (ALLTRIM(npad)) OF _MSYSMENU ;
PROMPT ALLTRIM(Prompt) MESSAGE ALLTRIM(Message)
DO DefinePop WITH popname, npad, dbfname
ENDSCAN
Die Prozedur DefinePop erstellt ein Popup, verbindet es mit dem dazugehörigen Eintrag
auf der Menüleiste und definiert alle Einträge.
PROCEDURE
DefinePop
LPARAMETERS
cPopup, cPadName, cTable
cPopup =
ALLTRIM(cPopup)
cPadName =
ALLTRIM(cPadName)
cTable =
ALLTRIM(cTable)
cOldAlias =
ALIAS()
DEFINE POPUP
(cPopup) RELATIVE MARGIN
ON PAD
(cPadName) OF _MSYSMENU ACTIVATE POPUP (cPopup)
LOCAL
cAction, cPad, cKey, cDefineString
IF
!USED(cTable)
USE (cTable) IN 0
ENDIF
SELECT
(cTable)
SCAN
cAction = ALLTRIM(action)
cBar = ALLTRIM(nBar)
cKey = ALLTRIM(hotkey)
cSkipFor = ALLTRIM(skipfor)
cDefineString = "DEFINE BAR " + cBar + ;
" OF " + cPopup + ;
" PROMPT '" + ALLTRIM(prompt) + "'"
IF !EMPTY(cKey)
cDefineString = cDefineString + " KEY " + cKey
ENDIF
IF !EMPTY(cSkipFor)
cDefineString = cDefineString + " SKIP FOR " + cSkipFor
ENDIF
&cDefineString
ON SELECTION BAR &cBar of (cPopup) &cAction
ENDSCAN
IF
!EMPTY(cOldAlias)
SELECT (cOldAlias)
ENDIF
RETURN
Wenn Sie eine datengesteuerte Menüengine wie diese einsetzen wollen, erstellen Sie am
besten eine Formularklasse mit Methoden, die den Definitionscode des Menüs verwalten.
Anschließend erstellen Sie ein Formular basierend auf dieser Klasse und setzen die
Eigenschaft DataSession des Formulars auf 2 - Private Data Session. Wenn Sie das Formular
in Ihrer Anwendung ausführen, benutzen Sie das Schlüsselwort NOSHOW, damit das Formular
zwar aufgebaut, aber nicht angezeigt, wird. Beispiel: DO FORMmenuform NOSHOW. Dann rufen
Sie die Methoden des Formulars auf, die das Menüsystem verwalten.
Über den Autor:
Rodney Hill ist bei der Microsoft Corporation in den USA beschäftigt. Die
Abdruckrechte wurden von Microsoft eingeräumt. Eine Danksagung geht an Randy Brown, Tom
Cooper und Ken Levy, welche diesen Artikel gegengelesen, fehlende Informationen aufgezeigt
und Änderungen angeregt haben. Liz Ruest hat den Artikel überarbeitet.
Microsoft, Windows und Visual FoxPro sind registrierte Warenzeichen der Microsoft
Corporation in den USA und in anderen Ländern. Andere Produkt- und Firmennamen können
Warenzeichen der jeweiligen Eigentümer sein.
[ 1 ] [ 2 ]
|