[ 1 ] [ 2 ]

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 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?

  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. Im Ereignis Activate des Formulars rufen Sie Ihr Menü auf. Befindet es sich beispielsweise in FORMMENU.MPR, benötigen Sie dafür folgenden Code:
  2. DO FormMenu.MPR
  3. 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 ]