![]() |
|
|
Studienarbeit - Für den Inhalt dieser Seite ist der Verfasser der Arbeit verantwortlich. |
Eine objektorientierte Scriptsprache für GUIs Studienarbeit Inhaltsverzeichnis
Python ist wie Tcl und Perl eine Scriptsprache, die besonders schnelle Programmentwicklung unterstützt. Die Stärken liegen vor allem in der Entwicklung von grafischen Oberflächen. In der Studienarbeit sollen nun einfache Scripte zur Demonstration der Möglichkeiten die Python bietet erstellt werden. Dabei wird das Betriebssystem UNIX (bzw. Linux) verwendet.
Nach Absprache mit Herrn Mecklenburg wurde entschieden, das von Ihm in Tcl/Tk geschriebene Programm "et" in Python zu programmieren. Da diese Aufgabe etwas umfangreicher ist als in der allgemeinen Aufgabenstellung gefordert, werden die Möglichkeiten von Python nicht an mehreren, sondern nur an diesem einen Script demonstriert. Damit lassen sich zwar nicht alle Anwendungsgebiete von Python darstellen, jedoch wäre dies im Rahmen einer Studienarbeit auch nicht möglich. Bei dem Programm "et" handelt es sich um eine grafische Bedienoberfläche für das PSST-Tool. Dieses Tool dient zum Plazieren von SDL-Prozessen auf parallelen Zielsystemen. Es analysiert den vom SDT-Tool erzeugten C-Code und legt im Dialog mit dem Benutzer die Verteilung des Systems fest.
Python ist eine interpretierte, interaktive, objektorientierte Programmiersprache. Die Entwicklung begann 1991 beim Stichting Mathematisch Centrum in Amsterdam. Als Guido van Rossum damals eine Testumgebung für ein neues Betriebssystem brauchte, aber keine geeignete Programmiersprache fand, entwickelte er kurzerhand Python. Damit war er in der Lage schnell kurze Testprogramme zu schreiben. Python hat eine sehr klare Syntax, eine übersichtliche Struktur und nur eine geringe Anzahl von Schlüsselwörtern. Nach kurzer Zeit stellten er und andere Anwender jedoch fest, daß Python für mehr als nur das Testen von Betriebssystemen nicht geeignet war, und so erweiterte man die Sprache; denn auf die Erweiterbarkeit von Python wurde schon bei der Entwicklung viel Wert gelegt. Neue Module lassen sich leicht in Python selbst oder wenn die Ausführungsgeschwindigkeit eine Rolle spielt, in C oder C++ programmieren. C-Programme (Module) können bei der Compilierung des Python-Interpreters bereits direkt integriert werden. Die zur Zeit aktuellste Distribution von Python ist die Version 1.4, die für fast alle Plattformen (UNIX, Linux, Windows 95, NT und 3.x, OS/2, Mac, ...) verfügbar ist, und zwar kostenlos, d. h. alles darf frei kopiert werden. Der Name Python hat übrigens nichts mit der gleichnamigen Schlangenart zu tun, sondern kommt von der britischen Comedy-Gruppe 'Monty Pythons Flying Circus', deren Fan Guido van Rossum ist.
Wie oben bereits erwähnt wurde ist Python eine Interpretersprache.
Es gibt drei Möglichkeiten ein Pythonprogramm auszuführen: interaktiv,
mit explizitem oder mit implizitem Interpreteraufruf.
Python 1.4 (Apr 27 1997) [GCC 2.7.2] Copyright 1991-1995 Stichting Mathematisch Centrum, Amsterdam >>> Im interaktiven Modus ist '>>>' der Standardprompt, der den Benutzer auffordert, einen Befehl einzugeben. Jeder Befehl wird vom Interpreter sofort ausgeführt und das Ergebnis ggf. angezeigt. Ist das Kommando am Ende einer Zeile noch nicht komplett, wird dies in der nächsten Zeile durch einen geänderten Prompt angezeigt ('...'). Möchte man ein Programm jedoch öfters aufrufen, wird man normalerweise
nicht im interaktiven Modus arbeiten, da hier das Programm jedesmal wieder
erneut eingegeben werden muß und auch keine Änderungen eines
einmal eingegebenen Befehls mehr vorgenommen werden können, sondern
schreibt das Programm mit einem x-beliebigen Texteditor. Ein Pythonprogramm
erhält normalerweise die Endung 'py',
dies ist jedoch nicht zwingend vorgeschrieben. Um das Programm zu starten,
gibt es zwei Varianten: entweder ruft man python
mit dem Programmnamen als Argument, oder man verwendet die #!-Konvention
und schreibt in die erste Zeile z.B. #!/usr/local/bin/python,
wodurch Python automatisch aufgerufen wird. Im Gegensatz zum interaktiven
Modus werden die Befehle in einem Rutsch vom Interpreter eingelesen und
dann ausgeführt. Nun gibt es einige Leute die bei dem Wort 'Interpreter' schon sofort
abwinken und auf einen Compiler schwören. Sicherlich hat ein Compiler
auch seine Vorzüge, wenn es um die Ausführungsgeschwindigkeit
geht und darum, daß das Ganze auch ohne ein weiteres Zusatzprogramm,
nämlich dem Interpreter, läuft. Aber auch der Python-Interpreter
hat mehrere Vorteile, die die Nachteile teilweise wieder wettmachen.
Ein Vorteil ist die Möglichkeit ein Programm schnell mal zu testen, da die Kompilation, die nach jeder kleinen Änderung notwendig wäre, entfällt. Beim Interpreter wird jede Anweisung erst zur Laufzeit übersetzt. Zur Geschwindigkeitssteigerung erzeugt Python jedoch einen sogenannten Bytecode, der eine interne Repräsentation des Programms darstellt. Dieser Bytecode ist dem tatsächlichen Programm noch ziemlich nahe und somit mit einer zeitaufwendigen Kompilation nicht zu vergleichen. Der Bytecode erhält die Endung 'pyc'. Ein weiterer Vorteil ist die Tatsache, daß Python plattformunabhängig ist. Es wird kein Maschinencode erzeugt, wie bei einem Compiler. Ein Programm, das sie auf einem PC schreiben, würde ohne weiteres z. B. auch auf einem Apple Macintosh laufen. Vorteil Nummer drei ist die Fehlertoleranz von Python. Python überprüft
jede Anweisung auf eventuelle Fehler bevor sie ausgeführt wird. Dadurch
sind Systemabstürze so gut wie ausgeschlossen. Tritt ein Fehler auf,
wird von Python eine sogenannte Ausnahme (engl.: exception) erzeugt. Auf
die Ausnahmebehandlung wird weiter unten noch etwas genauer eingegangen.
Diese Eigenschaften des Interpreters haben Python den Ruf gebracht,
daß hiermit eine schnelle Entwicklung von Prototypen zu realisieren
ist. In diesem Kapitel soll kurz die Blockstruktur von Python und die Möglichkeiten der Dokumentation eines Programms bzw. Moduls dargestellt werden. In jeder Sprache muß der Anfang und das Ende eines zusammengehörenden Blocks gekennzeichnet werden. In PASCAL werden dazu die Schlüsselwörter begin und end verwendet und in C die geschweiften Klammern. Nicht so in Python, hier bestimmt die Einrückung die Struktur des Programms. Somit sieht ein Pythonprogramm immer gut formatiert aus, da die Einrückung nicht freiwillig, wie bei den meisten anderen Sprachen, sondern zwingend vorgeschrieben ist. Dazu ein kleines Beispiel:
def summe(x):
if x==1:
return 1
return x+summe(x-1)
print summe(10)
In diesem Beispiel wird eine Funktion summe definiert, die einen Parameter x erwartet und dann rekursiv alle Zahlen von 1 bis x addiert. Die letzte Zeile gibt das Ergebnis von summe(10) auf dem Bildschirm aus. Wie man sieht, werden die Blöcke nur durch ihre Einrückung zusammengefaßt. Eine neue Ebene der Einrückung muß jeweils nach einem Doppelpunkt beginnen, wobei die Einrückungstiefe vollkommen gleichgültig ist; wichtig ist nur, daß diese innerhalb eines Blocks beibehalten wird. In diesem Fall wurde immer um 2 Zeichen eingerückt. Eine Sonderbehandlung erfahren Kommentare, mehrzeilige Strings und Klammerkonstruktionen.
Die Dokumentation von Modulen und der darin definierten Klassen und Funktionen, z.B. für grafische Browser, ist in Python auf einfachste Weise möglich: Ist die erste Anweisung in einer Definition ein String, dann wird dieser an das Attribut __doc__ zugewiesen. Ein Modul test.py soll dies verdeutlichen:
"""Hier kommt die Dokumentation des Moduls hin. Da es sich
meist um mehrzeiligen Text handelt, muß man die langen
Strings (die mit drei Anführungszeichen) verwenden. """
class Foo:
"""Die Klasse Foo dient der Erklärung von
Dokumentationsstrings."""
def bar(self):
"Auch einzelne Methoden können Dokumentation haben"
In Python greift man auf Attribute eines Objekts zu, indem man zwischen Objekt und Attribut einen Punkt setzt. Lädt man das Modul mit import test, dann stehen die Strings test.__doc__, test.Foo.__doc__ und test.Foo.bar.__doc__ zur Verfügung.
Python unterstützt die strukturierte Ausnahmebehandlung. Wenn der
Interpreter einen Fehler feststellt, wird eine Ausnahme generiert, und
anschließend beginnt die Suche nach einer Behandlung dieser Ausnahme.
Zuerst wird in der Funktion, in der der Fehler aufgetreten ist, geguckt,
ob die Ausnahme abgefangen wird. Wenn dies nicht der Fall ist, leitet der
Interpreter die Ausnahme an den Rufer weiter. Sollte die Ausnahme letztendlich
im Hauptprogramm angekommen sein, ohne daß sie vom Programm abgefangen
wurde, wird vom System eine Fehlermeldung ausgegeben und die Programmausführung
unterbrochen. Etwas anders ist dies bei den Modulen für die grafische
Oberfläche. Dort wird zwar auch eine Fehlermeldung ausgegeben, aber
das Programm läuft weiter, d. h. die Fenster auf der grafischen Oberfläche
bleiben erhalten.
Um die Ausnahme behandeln zu können, sprich abzufangen, muß man das Programmstück, bei dem die Ausnahme auftreten kann, in einen try-except-Block einschließen. Hinter der except-Anweisung kann als Argument die Ausnahme, auf die reagiert werden soll, angegeben werden. Ein optionales zweites Argument nimmt dann den Parameter auf, der den Fehler genauer beschreibt. Steht except für sich alleine, wird jede Ausnahme abgefangen. Nach einem try-Block dürfen beliebig viele except-Blöcke folgen, abgeschlossen von einem optionalen else-Block, der ausgeführt wird, wenn kein Fehler aufgetreten ist:
try:
f = open("test.txt", "r") # Öffnet test.txt zum lesen
except IOError,parameter:
# parameter beschreibt den I/O-Error
except:
# Irgendein anderer Fehler
else:
# Kein Fehler aufgetreten
Außer den Standardausnahmen von Python, lassen sich auch eigene
Ausnahmen erzeugen. Ausnahmen können Strings, Klassen oder Instanzen
von Klassen sein. Die Beschreibung der Möglichkeiten würde an
dieser Stelle jedoch zu weit führen.
Eine zweite Form auf Ausnahmen zu reagieren, ist der try-finally-Block. Tritt ein Fehler auf, springt das Programm in den finally-Block. Im Gegensatz zur except-Klausel, wird die Ausnahme hier allerdings nicht behandelt, sondern nur die Anweisungen in diesem Block ausgeführt. Damit hat man die Möglichkeit Aktionen anzugeben, die unbedingt ausgeführt werden sollen, bevor die Ausnahme eventuell vom Rufer abgefangen wird. Ein mögliches Einsatzgebiet ist das Schließen von Dateien, um bei einem Fehler keine geöffneten File-Objekte zurückzulassen.
Es wird heute wohl kaum noch einen modernen Rechnerplatz ohne eine grafische
Oberfläche, wie Microsoft Windows, X-Window, oder ähnliche, geben.
Deshalb muß eine moderne Anwendung, damit sie sich gut verkaufen
läßt, eine grafische Benutzerschnittstelle (GUI) haben. Dadurch
werden die Programme zwar nicht besser, aber komfortabler für den
Endanwender. Dieser braucht nicht mehr haufenweise Befehle auswendig lernen,
sondern wählt nur noch die gewünschte Anweisung aus einem Menü
aus oder klickt auf einen entsprechenden Knopf.
Wie oben schon beschrieben wurde, meldet auch Python sich nach dem Start
nur mit einer kurzen Meldung und erwartet dann vom Anwender eine Eingabe.
Ohne entsprechende Kenntnisse wird man jetzt nicht weiterkommen und kann
nur hoffen, daß das Handbuch in greifbarer nähe liegt.
Um ein Pythonprogramm nun mit einer grafischen Benutzeroberfläche
auszustatten, gibt es in Python mehrere Möglichkeiten.
Das am weitesten ausgereifte Modul ist Tkinter.
Dieses basiert auf dem Software-Paket Tcl/Tk und wird zur Zeit fast ausschließlich
eingesetzt. Da Tcl/Tk mittlerweile auch für fast alle Plattformen
verfügbar ist, sind die Programme, die Tkinter verwenden, portabel.
Ein weiteres Modul ist Rivet. Dieses stellt Funktionen zur Programmierung von Tk zur Verfügung, ohne das man den Tcl-Interpreter braucht. Dadurch wird die Ausführung in Tk wesentlich beschleunigt. Ein Nachteil ist jedoch die unterschiedliche Programmierschnittstelle zu Tkinter. Diesen Nachteil macht das Modul Trinket wieder weg, indem es die gleichen Funktionen wie Tkinter bereit stellt. Die beiden letzten Module befinden sich allerdings noch in der Entwicklung und sind somit in der aktuellen Distribution von Python noch nicht enthalten.
Da die letztgenannten Module für die meisten Anwender noch nicht zur Verfügung stehen, beschränkt sich die Programmierung hier auf Tkinter. Mit diesem Modul wurde eine Integration von Tk in Python vorgenommen. Der Hintergrund dafür war, daß mit Tk bereits eine leistungsfähige und durchdachte Bibliothek für grafische Oberflächen vorhanden ist. Das in Python geschriebene Modul Tkinter basiert auf dem Basismodul _tkinter, welches in C geschrieben wurde. Dieses verpackt die Anweisungen und schickt sie so an Tcl, daß sie dort ausgeführt werden können. Von diesem mehrstufigen Aufbau, wie er in Abb.1 dargestellt ist, bekommen weder der Programmierer noch der Anwender etwas mit. Tkinter stellt eine Reihe von Klassen bereit, mit denen die verschiedenen grafischen Elemente von Tk erzeugt und verändert werden können. Dadurch läßt sich vieles wesentlich einfacher schreiben, als dies in Tcl möglich wäre.
![]()
Ein kleiner Nachteil von Tkinter ist allerdings der, daß Tcl/Tk auf dem gleichen Rechner auch installiert werden muß. Unter Linux sollte das kein Problem sein, da hier Tcl/Tk standardmäßig bei eigentlich jeder Distribution mitgeliefert wird, und auch für andere Plattformen wie etwa Microsoft Windows und Apple Macintosh sind die neuen Versionen kostenlos erhältlich.
Tkinter basiert auf Tk, und Tk basiert seinerseits auf Widgets. Ein Widget steht für einen Bereich in einem Fenster, der ein bestimmtes Aussehen und eine bestimmte Funktion hat. Zum Beispiel steht ein Widget vom Typ Label für einen Bereich, in dem Text dargestellt werden kann. Tkinter stellt für alle gängigen Widgets von Tk eine entsprechende Klasse zur Verfügung. Die Klassen-Hierarchie von Tkinter zeigt Abb. 2.
![]()
Ein einfaches Beispiel, das ein Fenster zur Eingabe eines Textes ausgibt, zeigt das folgende Programm:
import Tkinter tk = Tkinter.Tk() f = Tkinter.Frame(tk, relief='ridge', borderwidth=2) f.pack() l = Tkinter.Label(f, text='Name:') l.pack(side='left') e = Tkinter.Entry(f, width=25, relief='sunken', borderwidth=2) e.pack() Tkinter.mainloop() Zuerst wird das Modul Tkinter geladen.
Um nun eine grafische Oberfläche zu erstellen, muß zuerst eine
Instanz (Objekt) der Klasse Tk erzeugt
werden. Diese braucht man, um ein Applikations-Fenster (Hauptfenster) zu
definieren. In dem Fenster werden dann ein Rahmen (Klasse Frame),
ein Schriftfeld (Klasse Label) und ein
Eingabefeld (Klasse Entry) erzeugt. Das
Aussehen wird über Schlüsselwortparameter definiert. Die Parameter
nennt man bei Widgets auch Ressourcen. relief
gibt die Umrandungsart, borderwidth die
Umrandungsdicke, text den auszugebenen
String und width die Breite des Elements
an. Mit der Methode pack wird jedes Widget
angezeigt. Diese Methode unterstützt wiederum Schlüsselwortparameter,
die angeben, wo das Widget plaziert werden soll. Für alle Ressourcen,
die nicht gesetzt werden, nimmt Tkinter Standardwerte an.
Bis zu diesem Zeitpunkt ist auf dem Bildschirm noch nichts zu sehen. Erst mit der letzten Zeile, in der die Methode mainloop aufgerufen wird, wird die Applikation dargestellt. mainloop ist eine Endlosschleife, die auf Eingaben des Anwenders wartet und darauf entsprechend reagiert.
![]()
In Tk gibt es eine Widget-Hierarchie. Das heißt, jedes Widget hat einen Parent, der immer als Erstes bei der Erzeugung der Instanz angegeben wird. Durch diese Gruppierung hat man ein wichtiges Gestaltungsmittel für den Aufbau der grafischen Oberfläche. In dem Beispiel hat der Rahmen die Applikation tk als Parent, er ist also ein Teil des Hauptfensters. Das Schrift- und das Eingabefeld haben als Parent den Rahmen (Widget der Klasse Frame). Dies bedeutet, daß sie innerhalb des Rahmens, und nicht daneben im Hauptfenster, plaziert werden. Daraus ergibt sich folgende Baumstruktur:
![]()
Für die drei wesentlichsten Komponenten der Internetunterstützung, stehen in Python entsprechende Module zur Verfügung, und zwar für:
Da dieses Thema doch sehr umfangreich ist und es ganze Bücher gibt,
die sich ausschließlich mit der Internetprogrammierung in Python
beschäftigen, soll an dieser Stelle nur soviel gesagt werden:
Es gibt zur Zeit einen mit der Unterstützung von Guido van Rossum entwickelten und komplett in Python programmierter Webbrowser namens 'Grail'. Damit lassen sich in Python geschriebene Applets laden und auf dem eigenen Rechner ausführen. Und auch für einige Webserver wird bereits Python anstelle von Perl eingesetzt.
In diesem Kapitel sollen einige Möglichkeiten von Python anhand eines Beispielskripts erläutert werden. Der Schwerpunkt wird dabei auf der Entwicklung der grafischen Oberfläche liegen.
Um sich in einem fremden Programmcode leichter zurechtzufinden, sollte dieser eine festgelegte Struktur haben. Auch in Python gibt es so eine (unverbindliche) Programmstruktur, die sich von der anderer Sprachen, wie z. B. Pascal oder C, eigentlich nicht unterscheidet. Ein Pythonprogramm besteht im allgemeinen aus folgenden Abschnitten:
Auch das Beispielskript besteht aus diesen vier Abschnitten, auf die, bis auf die sich wohl selbst erklärende Dokumentation, hier eingegangen wird.
Nach der Dokumentation folgt der Abschnitt der Modulimporte. In diesem Abschnitt werden alle benötigten Standard-Pythonbibliotheken geladen. Es gibt drei Formen der import-Anweisung, die hier zur Demonstration auch alle verwendet wurden:
import os import sys import string import Tkinter Damit werden die vier Module geladen und unter ihrem Namen im aktuellen Namensraum zur Verfügung gestellt, d. h. möchte man z. B. die Funktion _test von Tkinter aufrufen, muß man Tkinter._test() eingeben.
from Tkconstants import * Mit dieser Anweisung wird das Modul geladen und alle Variablen, Klassen und Funktionen des Moduls direkt im aktuellen Namensraum zur Verfügung gestellt. Der Name des Moduls braucht also nicht mehr mit angegeben werden. Ausgenommen sind alle Namen die mit einem Unterstrich beginnen, wie z. B. die eben angesprochene Funktion _test. Diese Anweisung sollte man nur anwenden, wenn man sicher ist, daß es zu keinen Überschneidungen mit den Namen in anderen Modulen kommt. Bei dem Modul Tkconstants, in dem Konstanten für die Programmierung mit Tkinter definiert sind, kann dies normalerweise nicht passieren, da dort alle Namen durchgehend groß geschrieben sind.
from Dialog import Dialog Lädt das Modul und fügt nur die angegebenen Namen in den aktuellen Namensraum ein. In diesem Fall nur die Klasse Dialog.
Da es sich bei Python um eine objektorientierte Programmiersprache handelt,
kann man nicht nur Funktionen, sondern auch Klassen definieren. Eine Klasse
definiert eine Menge von Objekten, die alle über die gleichen Methoden
(Funktionen), die in der Klasse definiert sind, verfügen. Objekte
sind Instanzen von Klassen.
In dem Beispielskript wurden drei Klassen definiert, die zeigen sollen
wie dies in Python gemacht wird. Nun handelt es sich hier allerdings nicht
nur um mein erstes Pythonprogramm, sondern auch um meinen ersten Versuch
objektorientiert zu programmieren. Ich hoffe, daß es mir wenigstens
einigermaßen gelungen ist.
Der folgende Programmauschnitt zeigt die Definition der Klassen und Funktionen:
class Info:
···
class SystemSetup(Info):
···
class Placing(Info):
···
def pipeopen(cmd):
···
def readline(fd):
···
Die Klasse Info erzeugt ein Info-Fenster,die Klasse SystemSetup fragt nach einigen Voreinstellungen und mit der Klasse Placing können die Prozesse dann plaziert werden. Die beiden Klassen SystemSetup und Placing haben Info als Basisklasse und erben somit deren Methoden. Es handelt sich bei den Klammerausdrücken also nicht um Parameter die übergeben werden, wie bei Funktionen, sondern um die Basisklasse(n).
Das Hauptprogramm wurde relativ kurz gehalten, da die meisten Aufgaben von den Methoden der Klassen ausgeführt werden:
if __name__ == "__main__":
tk = Tkinter.Tk()
tk.withdraw()
s = SystemSetup(tk)
staticframes, signallist, processlist = s.start()
if s.ok:
p = Placing(tk, staticframes, signallist, processlist)
p.start()
Der Name eines Moduls, einer Klasse oder einer Funktion wird in Python
im Attribut __name__ des jeweiligen Objekts
abgelegt. Dem Hauptprogramm wird grundsätzlich der Name __main__
zugewiesen. In dem Beispiel wird das Hauptprogramm von et.py
daher nur aufgerufen, wenn das Programm direkt mit Python (als Hauptprogramm)
gestartet wird. Importiert man et.py als
Modul, stehen alle Klassen und Funktionen zur Verfügung, das Hauptprogramm
wird allerdings nicht ausgeführt.
Im Hauptprogramm wird zuerst eine Instanz der Klasse Tk
erzeugt und der Variablen tk zugewiesen.
Da jede Klasse ihre eigenen Fenster erzeugt, wird das Hauptfenster nicht
benötigt und somit durch Aufrufen der Methode withdraw
der Instanz tk unsichtbar geschaltet.
Im weiteren Programmverlauf werden noch ein bzw. zwei weitere Instanzen
erzeugt, und mit der Methode start wird
die grafische Oberfläche aufgebaut.
Eine Eigenschaft von Python läßt sich hier noch sehr gut erkennen: Der Aufruf s.start() liefert 3 Werte zurück, die man direkt an 3 Variablen (durch Komma getrennt) zuweisen kann.
Die grafische Benutzerschnittstelle von et.py
besteht, sieht man von dem Dialog-Fenster für Fehlermeldungen, Fragen,
usw. ab, aus insgesamt fünf verschiedenen Fenstern. An zwei Fenstern
soll nun beispielhaft die Gestaltung einer grafischen Oberfläche in
Python erläutert werden. Die angegebenen Programmstücke sind
Ausschnitte aus dem Beispielskript, wie es im Anhang komplett abgedruckt
ist. Die folgenden Bilder wurden mit Windows 95 erzeugt. Unter Linux werden
Fenster, je nach verwendetem Window-Manager, etwas anders aussehen.
Startet man das Programm, meldet sich dieses mit einem Fenster wie in Abb. 5. Aber wie erzeugt man nun mit Python dieses Fenster?
![]()
Als erstes wird ein eigenes Fenster benötigt. Dazu benutzt man die Tkinter-Klasse Toplevel. Eine Instanz dieser Klasse erzeugt ein Widget, das vom Window-Manager kontrolliert wird. Wie bei jeder Erzeugung einer Instanz für ein Widget, ist das erste Argument der Parent des Toplevel-Widgets. Anschließend vergibt man am besten auch gleich den Namen des Fensters und des Icons:
self.top = Tkinter.Toplevel(master)
self.top.title("ET")
self.top.iconname("ET")
Die Angabe von self vor einem Namen, innerhalb einer Methode, bezieht sich auf das Objekt selbst; somit handelt es sich hier um eine Instanzvariable. Instanzvariablen sind Variablen, von denen es eine Kopie pro Instanz (Objekt) gibt und auf die man nur über diese Instanz zugreifen kann.
In der oberen Hälfe des Fensters befinden sich die Eingabemöglichkeiten, deren Aufbau aus Frame-, Label- und Entry-Widget schon aus dem Kapitel Widgets bekannt ist:
self.topframe = Tkinter.Frame(self.top, relief=RAISED, borderwidth=2) self.topframe.pack(side=TOP,fill=X) self.sdl_label = Tkinter.Label(self.topframe, text="SDL system name") self.sdl_label.pack(side=TOP, anchor=CENTER) self.sdl_entry = Tkinter.Entry(self.topframe, textvariable=self.sys_name) self.sdl_entry.pack(side=TOP, fill=X) self.midframe = Tkinter.Frame(self.top, relief=RAISED, borderwidth=2) self.midframe.pack(side=TOP, fill=X) self.exe_label = Tkinter.Label(self.midframe, text="executeable name") self.exe_label.pack(side=TOP, anchor=CENTER) self.exe_entry = Tkinter.Entry(self.midframe, textvariable=self.exe_name) self.exe_entry.pack(side=TOP, fill=X) self.exe_entry.insert(0, "test") Neu bei der Methode pack (Geometrie-Manager) sind die Ressourcen fill und anchor. Mit fill wird angegeben, wie sich das Widget an den vom Geometrie-Manager reservierten Platz anpaßt, wenn das Fenster vom Anwender vergrößert wird. Durch X, dessen Wert im Modul Tkconstants definiert ist, paßt sich das Widget in X-Richtung an das veränderte Fenster an. Der Standardwert von fill ist None. None dient als Platzhalter für Variablen die eigentlich keinen Wert haben. Mit anchor gibt man die Ausrichtung des Widget im vom Geometrie-Manager reservierten Platz an. In der Variable hinter dem Parameter textvariable, wird der String aus dem Eingabefeld abgespeichert. Mit der Methode insert wird der String "test" an der Position 0 in das Eingabefeld eingefügt.
Für die Eingabe der statischen Frames wurde ein Scale-Widget verwendet. Damit lassen sich über eine Skala nur vorgegebene Werte einstellen, und somit kann die Abfrage ob eine Eingabe sinnvoll ist entfallen:
self.botframe = Tkinter.Frame(self.top)
self.botframe.pack(side=TOP, fill=X, padx=5, pady=5)
self.frm_label = Tkinter.Label(self.botframe, text="Number of static frames")
self.frm_label.pack(side=TOP)
self.frm_scale = Tkinter.Scale(self.botframe, from_=1, to=20,
tickinterval=19, orient=HORIZONTAL)
self.frm_scale.pack(side=TOP, fill=X)
self.frm_scale.set(1)
Der Wertebereich der Skala reicht von 1 (Ressource from_)
bis 20 (Ressource to) mit einer Skaleneinteilung
von 19 (Ressource tickinterval), dadurch
läßt sich der Wert in Einerschritten ändern. Mit dem Schlüsselwortparameter
orient wird die Ausrichtung in horizontaler
oder vertikaler Richtung angegeben, und mit der Methode set
wird der Schieber zu Anfang auf 1 gesetzt.
Zum Schluß müssen noch die drei Knöpfe im unteren Teil des Fensters plaziert werden, um weitere Aktionen ausführen zu können:
self.ok_button = Tkinter.Button(self.top, text="OK", command=self.ok_command) self.ok_button.pack(side=LEFT, expand=ON, padx=5, pady=5) self.cancel_button = Tkinter.Button(self.top, text="Cancel", command=self.cancel_command) self.cancel_button.pack(side=LEFT, expand=ON, padx=5, pady=5) self.info_button = Tkinter.Button(self.top, text="Info", command=self.info_command) self.info_button.pack(side=LEFT, expand=ON, padx=5, pady=5) Einen Knopf läßt sich mit der Klasse Button
erstellen. In diesem Beispiel haben die Knöpfe keinen Frame als Parent,
sondern das Toplevel-Widget. Der Ressource
command kann eine Funktion oder Methode
übergeben werden, die immer dann aufgerufen wird, wenn der Knopf vom
Benutzer gedrückt wird.
Sobald das Programm nun in die Hauptschleife (Methode mainloop) eintritt, wird ein Fenster wie in Abb. 5 auf dem Bildschirm erscheinen.
Bei dem zweiten Beispiel handelt es sich um ein Fenster, dessen genaues Aussehen von einer Variablen abhängig ist, und bei dem ein anderer Geometrie-Manager verwendet wird.
![]()
Die Erzeugung eines Fensters geschieht analog zum obigen Beispiel und braucht deshalb an dieser Stelle nicht noch einmal wiederholt werden. Unabhängig von der Anzahl der statischen Frames ist die erste Zeile des Fensters:
self.heading1 = Tkinter.Label(self.env_top, text="enable") self.heading1.grid(row=0, column=1) self.heading2 = Tkinter.Label(self.env_top, text="env. name") self.heading2.grid(row=0, column=2) Die Methode grid zum Plazieren der Widgets
arbeitet mit Zeilen (row) und Spalten (column).
Die Breite einer Zeile oder Spalte richtet sich nach dem breitesten Widget,
das beim Aufbau des Fensters in dieser Zeile oder Spalte ist.
Der weitere Aufbau geschieht tabellenförmig, wozu der Geometrie-Manager grid sehr gut geeignet ist:
for i in range(staticframes+1):
if i == staticframes:
text = "dynamic frames"
else:
text = "frame "+`i`
self.framenames = Tkinter.Label(self.env_top, text=text)
self.framenames.grid(row=1+i, column=0)
self.enable.append(Tkinter.BooleanVar())
self.enable_env.append(Tkinter.Checkbutton(self.env_top, variable=self.enable[i]))
self.enable_env[i].grid(row=1+i, column=1)
self.names.append(Tkinter.StringVar())
self.env_names.append(Tkinter.Entry(self.env_top,textvariable=self.names[i]))
self.env_names[i].grid(row=1+i, column=2)
In dem Beispiel für Abb. 6 wird die Schleife 4 mal durchlaufen
(staticframes = 3). Jede Zeile besteht
aus einem Label-, einem Checkbutton-
und einem Entry-Widget. Ein Checkbutton
ist ein Knopf, der entweder ein- oder ausgeschaltet sein kann. Da der Zustand
der Checkbutton und der Inhalt der Eingabefelder in Variablen abgespeichert
werden muß, benutzt man dafür Listen. In Python sind Listen
veränderbare Folgen von Objekten, die einen indizierten Zugriff unterstützen.
Mit der Methode append kann ein neues Element
am Ende der Liste angefügt werden. Wie man damit eine Liste von Widgets
erzeugt, verdeutlicht obiger Programmausschnitt.
Hiermit soll die Vorstellung der grafischen Möglichkeiten in Python beendet werden, denn die anderen Fenster sind in einer ähnlicher Art und Weise aufgebaut.
Meine persönliche Meinung zu Python ist, daß es sich um eine
leistungsfähige und leicht zu erlernende Sprache handelt, die sich
für kurze Testprogramme genauso gut eignet, wie für umfangreichere
Projekte. Und durch die immer größer werdende Anzahl von Python-Anwendern,
kann man davon ausgehen, daß die Entwicklung auch in Zukunft weitergehen
wird. Die neuesten Distributionen von Python kann sich jeder kostenlos
im Internet besorgen.
Hier konnte nur ausschnittsweise auf auf die Möglichkeiten von Python eingegangen werden. Hinweise auf weiterführende Literatur und Internetadressen befinden sich am Ende der Studienarbeit.
#!/usr/local/bin/python
# *** Studienarbeit ***
# --------------------------
# Programm : et.py
# Sprache : Python 1.4
# Autor : Markus Merten
# Matr.-Nr.: 294621
# Datum : 19.06.1997
# --------------------------
# Module importieren
import os
import sys
import string
import Tkinter
from Tkconstants import *
from Dialog import Dialog
class Info:
"""
############################################################################
Klasse : Info
Basisklasse : -
Beschreibung : Wärend der Initialisierung wird ein Info-Fenster erzeugt.
Dieses stellt eine kurze Information zu diesem Programm
und der momentan ausfürbaren Aktionen dar.
Durch die Methoden 'show_info' und 'hide_info' wird das
Fenster sichtbar bzw. unsichtbar geschaltet.
Init-Parameter : Üergeordnetes Widget (master), Hilfetext
############################################################################
"""
def __init__(self, master, helptext):
self.info_top = Tkinter.Toplevel(master)
self.info_top.transient(master)
self.info_top.geometry("400x300+347+234")
self.info_top.positionfrom(who="user")
self.info_top.withdraw()
self.info_top.title("ET info")
self.info_top.iconname("ET info")
self.info_top.protocol("WM_DELETE_WINDOW", self.hide_info)
logopath = os.environ["EPSYLONKERNEL"]
self.g_frame = Tkinter.Frame(self.info_top, relief=RIDGE, bd=2)
self.g_frame.pack(side=TOP, fill=X, padx=3, pady=3)
self.logo = Tkinter.Label(self.g_frame, bitmap="@"+logopath+"/etlogo.xbm")
self.logo.pack(side=LEFT, expand=ON)
self.label = Tkinter.Label(self.g_frame, justify=LEFT, wraplength="8c",
text="ET stellt dem Benutzer eine grafische "
"Bedienoberfläche fiür das PSST-Tool zur "
"Verfügung. Dieses macht das Plazieren "
"von SDL-Prozessen kom- fortabler und "
"übersichtlicher.")
self.label.pack(side=LEFT, expand=ON)
self.s_frame = Tkinter.Frame(self.info_top, relief=RIDGE, bd=2)
self.s_frame.pack(side=TOP, expand=ON, fill=BOTH, padx=3, pady=3)
self.help = Tkinter.Label(self.s_frame, justify=LEFT, wraplength="13c",
text=helptext)
self.help.pack(side=TOP, pady=5)
self.OK_button = Tkinter.Button(self.s_frame, text="OK",
command=self.hide_info)
self.OK_button.pack(side=BOTTOM, pady=5)
def show_info(self):
self.info_top.grab_set()
self.OK_button.focus_set()
self.info_top.deiconify()
def hide_info(self):
self.info_top.grab_release()
self.info_top.withdraw()
class SystemSetup(Info):
"""
############################################################################
Klasse : SystemSetup
Basisklasse : Info
Beschreibung : Hier können die Voreinstellungen, wie z. B. die Anzahl der
statisches Frames, eingegeben werden. Anschließend wird
das Programm 'psst' gestartet und die Parameter übergeben.
Sind die Parameter in Ordnung, wird die Signal- und die
Prozeßliste eingelesen.
Init-Parameter : Übergeordnetes Widget (master)
############################################################################
"""
def __init__(self, master):
self.master = master
self.signallist = []
self.processlist = []
self.sys_name = Tkinter.StringVar()
self.exe_name = Tkinter.StringVar()
self.top = Tkinter.Toplevel(master)
self.top.title("ET")
self.top.iconname("ET")
self.top.protocol("WM_DELETE_WINDOW", self.cancel_command)
self._createWidgets()
Info.__init__(self, self.top, "Geben Sie den Namen des SDL-Systems "
"(ohne Endung!) und den Namen, den das "
"ausführbare Programm erhalten soll, ein. "
"Die Anzahl der statischen Frames kann "
"von 1 bis max. 20 eingestellt werden.\n"
"Zeigt sich nach dem Drücken auf
Die Fenster des Beispielskripts
Die folgenden Abbildungen zeigen die Fenster von et.py.
Als Beispiel wurden generation als SDL-Systemname, test als
Name des ausführbaren Programms und 3 statische Frames gewählt.
Die Bilder wurden aus technischen Gründen alle unter Windows 95 erzeugt. Das hier abgedruckte Programm in seiner Originalfassung läuft jedoch nur unter Linux!
![]()
![]()
![]()
![]()
Die vollständige Grammatik von Python in erweiterter Backus-Naur-Form (EBNF). Im einzelnen bedeuten
single_input : NEWLINE | simple_stmt
| compound_stmt NEWLINE.
file_input : {NEWLINE | stmt} ENDMARKER.
eval_input : testlist {NEWLINE} ENDMARKER.
stmt : simple_stmt | compound_stmt.
simple_stmt : small_stmt {';' small_stmt} [';'] NEWLINE.
small_stmt : expr_stmt | print_stmt
| del_stmt | pass_stmt | flow_stmt
| import_stmt | global_stmt | exec_stmt.
expr_stmt : testlist {'=' testlist}.
print_stmt : 'print' {test ','} [test].
del_stmt : 'del' exprlist.
pass_stmt : 'pass'.
flow_stmt : break_stmt
| continue_stmt
| return_stmt
| raise_stmt.
break_stmt : 'break'.
continue_stmt : 'continue'.
return_stmt : 'return' [testlist].
raise_stmt : 'raise' test [',' test [',' test]].
import_stmt : 'import' dotted_name {',' dotted_name}
| 'from' dotted_name 'import' ('*' | NAME {',' NAME}).
dotted_name : NAME {'.' NAME}.
global_stmt : 'global' NAME {',' NAME}.
exec_stmt : 'exec' expr ['in' test [',' test]].
compound_stmt : if_stmt | while_stmt | for_stmt
| try_stmt | funcdef | classdef.
if_stmt : 'if' test ':' suite
{'elif' test ':' suite} ['else' ':' suite].
while_stmt : 'while' test ':' suite ['else' ':' suite].
for_stmt : 'for' exprlist 'in' testlist ':'
suite ['else' ':' suite].
try_stmt : 'try' ':' suite except_clause ':' suite
{except_clause ':' suite} ['else' ':' suite]
| 'try' ':' suite 'finally' ':' suite.
except_clause : 'except' [test [',' test]].
suite : simple_stmt
| NEWLINE INDENT stmt {stmt} DEDENT.
test : and_test {'or' and_test} | lambdef.
and_test : not_test {'and' not_test}.
not_test : 'not' not_test | comparison.
comparison : expr {comp_or expr}.
comp_op : '<' | '>' | '==' | '>='
| '<=' | '<>' | '!=' | 'in'
| 'not' 'in' | 'is' | 'is' 'not'.
expr : xor_expr {'|' xor_expr}.
xor_expr : and_expr {'^' and_expr}.
and_expr : shift_expr {'&' shift_expr}.
shift_expr : arith_expr {('<<'|'>>') arith_expr}.
arith_expr : term {('+'|'-') term}.
term : factor {('*'|'/'|'%') factor}.
factor : ('+'|'-'|'~') factor | power.
power : atom {trailer} {'**' factor}.
atom : '(' [testlist] ')' | '[' [testlist] ']'
| '{' [dictmaker] '}' | '`' testlist '`'
| NAME | NUMBER | STRING {STRING}.
lamdef : 'lambda' [varargslist] ':' test.
trailer : '(' [arglist] ')' | '[' subscriptlist ']' | '.' NAME.
subscriptlist : subscript {',' subscript} [','].
subscript : '.' '.' '.' | test | [test] ':' [test] [sliceop].
sliceop : ':' [test].
exprlist : expr {',' expr} [','].
testlist : test {',' test} [','].
dictmaker : test ':' test {',' test ':' test} [','].
classdef : 'class' NAME ['(' testlist ')'] ':' suite.
funcdef : 'def' NAME parameters ':' suite.
parameters : '(' [varargslist] ')'.
varargslist : {fpdef ['=' test] ','}
('*' NAME [',' ('**'|'*' '*') NAME]
| ('**'|'*' '*') NAME)
| fpdef ['=' test] {',' fpdef ['=' test]} [','].
fpdef : NAME | '(' fplist ')'.
fplist : fpdef {',' fpdef} [','].
arglist : argument {',' argument} [','].
argument : [test '='] test.
NAME Python's basic power can be extended with your own module written in
C or C++. On most systems such modules may be dynamically loaded. Python
is also adaptable as an extension language for existing applications. See
the internal documentation for hints.
-i When a script is passed as first argument or the -c
option is used, enter interactive mode after executing the script or the
command. It does not read the $PYTHONSTARTUP file. This can be useful to
inspect global variables or a stack trace when a script raises an exception.
-s Suppresses the automatic printing of expressions entered in
interactive mode (useful when input is actually generated e.g. by Emacs).
-u Force stdout and stderr to be totally unbuffered.
-v Print a message each time a module is initialized, showing
the place (filename or built-in module) from which it is loaded.
-c command Specify the command to execute (see next section). This terminates the
option list (following options are passed as arguments to the command).
If available, the script name and additional arguments thereafter are
passed to the script in the Python variable sys.argv, which is a
list of strings (you must first import sys to be able to access
it). If no script name is given, sys.argv is empty; if -c
is used, sys.argv[0] contains the string æ-cÆ. Note that options
interpreted by the Python interpreter itself are not placed in sys.argv.
In interactive mode, the primary prompt is æ>>>Æ; the second prompt (which appears when a command is not complete) is æ...Æ. The prompts can be changed by assignment to sys.ps1 or sys.ps2. The interpreter quits when it reads an EOF at a prompt. When an unhandled exception occurs, a stack trace is printed and control returns to the primary prompt; in non-interactive mode, the interpreter exits after printing the stack trace. The interrupt signal raises the KeyboardInterrupt exception; other UNIX signals are not caught (except that SIGPIPE is sometimes ignored, in favor of the IOError exception). Error messages are written to stderr. /usr/local/bin/python Python Library Reference Python Reference Manual CNRI 1895 Preston White Drive Reston, VA 20191 USA E-mail: guido@cnri.reston.va.us, guido@python.org FTP site: ftp://ftp.python.org Newsgroup: comp.lang.python
While CWI is the initial source for this software, a modified version
is made available by the Corporation for National Research Initiatives
(CNRI) at the Internet address ftp://ftp.python.org.
STICHTING MATHEMATISCH CENTRUM AND CNRI DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM OR CNRI BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. Für die Ausarbeitung dieser Studienarbeit verwendete Literatur:
Weitere Literatur in englischer Sprache:
Python Internetadressen:
|
|
Unser Server befindet sich immer im Aufbau.
© 1997 Labor für Parallelverarbeitung, Fachhochschule Bielefeld Letzte Änderung am 2008-11-17 durch Markus Merten Wünschenswertes und Anregungen bitte an: webmaster@parallel.fh-bielefeld.de |