Erstellen von Menüs in Visual FoxPro - dFPUG

Werbung
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:
1.
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.
2.
Sie generieren das Visual FoxPro-Menü (eine Programmdatei mit der Erweiterung .MPR).
3.
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 FormularDesigner 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?
1.
Erstellen Sie im Menü-Designer ein Menü mit den zu dem Formular gehörenden Einträgen.
2.
Wenn der Menü-Designer aktiv ist, wählen Sie im Menü „Ansicht“ den Eintrag „Allgemeine Optionen...“
3.
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.
4.
Klicken Sie im Menü-Designer auf die Schaltfläche „Optionen“, um den Dialog „Optionen zur
Bezeichnung“ zu öffnen.
5.
Definieren Sie hier einen Tastentext, den Sie benötigen, wenn Sie den Eintrag aus der Menüleiste löschen.
6.
Generieren Sie den Menücode.
Das Menü mit dem Formular verbinden:
1.
2.
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
DEFINE
ON PAD
ON PAD
PAD p1 OF _example PROMPT "\<Datei"
PAD p2 OF _example PROMPT "\<Farbe"
p1 OF _example ACTIVATE POPUP file
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 ShortcutMenü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",
bar2 = CREATEOBJECT("mBar",
bar3 = CREATEOBJECT("mBar",
pop1 = CREATEOBJECT("mPop",
pop1.AddBar(bar1)
pop1.AddBar(bar2)
pop1.AddBar(bar3)
pad1 = CREATEOBJECT("mPad",
pad1.SetPopup(pop1)
"Test1", "bar1", "MESSAGEBOX(PROMPT())")
"Test2", "bar2", "MESSAGEBOX(PROMPT())")
"Done", "bar3", "POP MENU _MSYSMENU")
"pop1")
"Pad1", "No message")
* 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
_MSM_FILE
\<Datei
Öffnen, Schließen, _MFILE
Speichern usw.
FILE
_MSM_EDIT
\<Bearbeiten
Kopieren,
Ausschneiden,
Einfügen usw.
EDIT
_MEDIT
DBFNAME
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
SKIPFO
HOTKE
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.
Herunterladen