Zusammenfassung:
Dieses ist der dritte Artikel unserer Reihe über das GL Utility Toolkit
(GLUT), das von Mark Kilgard geschrieben wurde. GLUT erleichtert
die Benutzung von OpenGL beim Entwickeln von Programmen, da es den
architekturabhängigen Teil einer OpenGL Anwendung hinter einem einfach
erlernbaren und einfach benutzbaren API verbirgt.
Wie wir in den vornagegangenen Artikeln gesehen haben, enthält OpenGL aus Designgründen nur die architekturunabhängigen Teile eines fortgeschrittenen 3D APIs. Das Öffnen von Fenstern, das Behandeln von Tastatureingaben usw. hängen stark von der verwendeten Plattform ab und sind daher nicht Teil von OpenGL. GLUT löst diese Probleme: GLUT erlaubt die einheitliche Behandlung von Dingen wie Fenstern, double buffering, Textdarstellung, Tastatureingabe und Menüs auf verschiedenen Architekturen.
Heute werden wir uns näher mit der Verwendung von Menüs in unseren OpenGL Anwendungen beschäftigen. In unserem vorhergehenden Artikel Fenstermanagement haben wir gezeigt wie wir Benutzereingaben durch hot keys erhalten können. Menüs sind eine weitere Möglichkeit der Kommunikation zwischen der Benutzerin und unserer Anwendung. GLUT fängt Tastatur- und Mausevents ab und erlaubt es, Callbackfunktionen anzugeben, um diese Ereignisse zu verarbeiten. Hot Keys haben den Nachteil, daß sie unsichtbar sind, so daß die Benutzerin ein Handbuch lesen muß und sich später daran erinnern muß, welche Taste die gewünschte Aktion auslöst. Menüs sind im Gegensatz dazu viel flexibler, da sie graphisch dargestellt werden und der Benutzerin anzeigen, welche Optionen gerade verfügbar sind.
Wir verwenden das Programm in ../../common/May1998/example1.tar.gz als Beispiel. Es ist das Beispiel aus dem letzten Artikel über Fenstermanagement mit leichten Veränderungen. Das Programm sollte mit dem mitgelieferten Makefile übersetzt werden.
Wir benötigen eine OpenGL Bibliothek (z.B. die Mesa Bibliothek) und die GLUT Bibliothek, um das Programm zu übersetzen. Beide sind weitverbreitet und in den meisten Linux Distributionen enthalten. Nach erfolgreichem Übersetzen erhalten wir das ausführbare Programm example1. Nach dem Start sollte es ein Fenster mit einem farbigen Dreieck mit einer roten, grünen und blauen Ecke öffnen (s. die Abbildung links).
Das Fenster enthält einen Hauptteil mit schwarzem Hintergrund und dem Dreieck in der Mitte und einem Unterfenster mit grauem Hintergrund und etwas Text. Unser Beispiel ist eine Echtzeitanimation und der Eintrag neben dem Text Time: sollte sich ständig ändern.
Bewege die Maus auf den Hauptteil des Fensters und Drücke die linken Maustaste. Das löst ein Ereignis aus, das von unserem Beispiel verarbeitet wird und das folgende Menü öffnen sollte:
Das Menü enthält drei Aktionen (Drehung einschalten, Verschiebung einschalten, Farbe verändern) und eine Option "Quit", um das Programm zu beenden. Bewege den Mauszeiger mit gedrückter linker Maustaste auf jede Aktion und probiere aus, was passiert.
Das Auswählen von "Rotation On" veranlaßt das Dreieck dazu, sich unerläßlich um seinen Schwerpunkt zu drehen, "Translation On" bewegt das Dreieck horizontal durch das Fenster, wobei Teile die rechts verschwinden links wieder erscheinen. "Change Color" öffnet ein Untermenü mit den folgenden Punkten:
Das ist ein sehr einfaches Beispiel für die Verwendung von Menüs in einem OpenGL Programm. Die Darstellung von Menüs und Untermenüs ist plattformabhängig. Die hier gezeigten Bilder entsprechen der Darstellung unter Linux GLUT. Wenn das Beispiel unter Windows 95/NT verwendet wird, sehen die Menüs ganz anders aus. Wichtig ist, daß die Funktionalität durch die Verwendung der GLUT Bibliothek portabel bleibt.
Das Hauptmenü enthält zwei verschiedene Arten von Einträgen: die der ersten Art (Rotation On, Translation On) verändern sich, wenn die entsprechende Aktion ausgeführt wird; nachdem das Dreieck in Drehung versetzt wurde, enthält das Menü den Eintrag "Rotation Off". Die Einträge der zweiten Art verändern sich nicht, wie z.B. "Change Color", "Red", "Blue" und "Green".
Es gibt noch einige weitere interessante Dinge, auf die ich den Leser aufmerksam machen möchte, bevor ich beschreibe, wie man diese Menüs programmiert. Unser Beispiel im letzten Artikel Fenstermanagement hatte zwei Hot Keys. Diese waren "q" für "quit" und "i", um den Informationsteil ein- und auszuschalten. Probiere sie aus, sie funktionieren immer noch.
Wenn man den Cursor in den (eingeschalteten) Informationsteil im grau hinterlegten Teilfenster bewegt und die linke Maustaste drückt, sollte man dieses Menü erhalten:
Das zeigt, daß Menüs nicht nur mit bestimmten Ereignissen verbunden sind (linke Maustaste), sondern auch vom gegenwärtigen OpenGL Kontext abhängen können. Wir haben im letzten Artikel schon erklärt, daß jedes Teilfenster in GLUT seinen eigenen OpenGL Kontext hat; hier sehen wir eine weitere Auswirkung dieser Tatsache. Zwei verschiedene Menüs entsprechen dem selben Ereignis in unterschiedlichen Kontexten. Das erlaubt es der Entwicklerin, ausgefeilte Benutzerschnittstellen zu programmieren.
Noch interessanter ist, daß das Ausschalten des Informationsteils mit der "i"-Taste es unmöglich macht, den "This is a dummy menu" Eintrag zu erhalten. Warum? Weil das Ausschalten des Unterfensters den kompletten Kontext (einschließlich zugehöriger Menüs) ausschaltet.
Damit sollten wir anfangen, das Programm im einzelnen zu beschreiben. Ich gehe davon aus, daß die Leserin mit OpenGL/GLUT wie es in den vorhergehenden Artikeln dargestellt wurde, vertraut ist. Die Funktion main() enthält mehrere Abschnitte. Die Reihenfolge dieser Abschnitte ist wichtig:
All diese Abschnitte, mit Ausnahme der Menüerzeugung, sollten der Leserin bekannt sein. Ein kurzer Blick auf den Code, der die Menüs erzeugt, zeigt, wie einfach er ist. Menüs werden durch den Aufruf int glutCreateMenu( void (f*)(int) ) erzeugt, wobei f eine callback Funktion ist, die die Nummer des ausgewählten Menüeintrags erhält und eine entsprechende Aktion ausführt. Der Rückgabewert von glutCreateMenu ist ein Integer, der das gerade erzeugte Menü eindeutig identifiziert.
Auch die Funktionen, die als callbacks die Menüevents verarbeiten, sind sehr einfach. Die Routinen void mainMenu(int) und void subMenu(int) enthalten im Grunde nur einen switch, der die Aktionen der einzelnen Menüeinträge enthält.
Nach der Erzeugung eines Menüs fügen wir Einträge mit der Funktion void glutAddMenuEntry(char *s, int nr) hinzu, wobei der Parameter s den Text des Menüeintrages anthält und der Parameter nr die Nummer enthält, die an den callback weitergereicht wird, wenn dieser Eintrag ausgewählt wird. Man sollte natürlich identische Nummern für verschiedene Einträge im selben Menü vermeiden.
Untermenüs können mit der Funktion void glutAddSubMenu(char *s, int nr) zu einem Menü hinzugefügt werden.
Wenn das Menü vollständig zusammengestellt ist, wird es schließlich mittels glutAttachMenu mit einem bestimmten Eingabeevent verbunden. Diese Funktion kann auch GLUT_RIGHT_BUTTON und GLUT_MIDDLE_BUTTON verwenden.
Menüeinträge können mit dem Befehl void glutChangeToMenuEntry(int entry, char *s, int value) verändert werden. Der Befehl ändert den Eintrag mit der Nummer entry in dem Menü, das mit dem aktuellen Fenster und Kontext verbunden ist: der Eintrag ist nach diesem Befehl mit dem Text in der Variablen s beschriftet und gibt den Wert value an die callback Funktion weiter. Wir haben in unserem Beispiel
glutChangeToMenuEntry(2, "Translation On", 2);benutzt, um den Eintrag Nummer 2 im Hauptmenü neu zu beschriften.
GLUT erlaubt noch viel mehr: man kann einen Menüeintrag durch ein Untermenü ersetzen (und umgekehrt), Menüeinträge löschen, ganze Menüs entfernen und vieles mehr. Wir werden uns dem hier nicht weiter widmen, da ich glaube, daß das vorliegende Beispiel einfach und funktional genug ist, um den meisten Benutzern zu genügen. Wer weitere Funktionen benötigt, möge einen Blick in das neueste GLUT Manual werfen.
Webpages maintained
by Miguel Ángel Sepúlveda
© Miguel Ángel Sepúlveda 1998 Übersetzt von:unbekannt LinuxFocus 1998 |