Einführung in Tcl/Tk, Teil 4

Aus LinuxUser 10/2000

Einführung in Tcl/Tk, Teil 4

Die Kommandozeile macht sich schön (2)

In der vierten und letzten Folge dieser Tcl/Tk-Einführung fügen wir der in Teil drei entstandenen Steuerungsoberfläche für Povray Funktionalität hinzu und erwecken sie so zum Leben.

In Abbildung 1 ist die im dritten Teil dieser Einführung erzeugte Oberfläche zur Steuerung des Raytracers Povray zu sehen. Bisher tut sie allerdings noch nichts außer sich selbst zu beenden, wenn Sie mit der Maus auf den Menübutton Datei–>Beenden klicken.

Abbildung 1: Die Oberfläche der Povray-Steuerung

Abbildung 1: Die Oberfläche der Povray-Steuerung

Der Quelltext für das komplette grafische Benutzerinterface inklusive der Funktionen, die diesmal hinzu gefügt werden, ist in Listing 1 abgedruckt. Sie können ihn abschreiben, in einer Datei namens povgui speichern, mit chmod +x povgui ausführbar machen und aufrufen – vorausgesetzt, Sie haben sich nicht verschrieben und Ihr Tcl/Tk-Interpreter hört auf den Namen wish. Eventuell müssen Sie den Aufruf exec wish “$0” in Zeile 3 durch exec wish8.0 “$0” oder eine andere Versionsnummer ersetzen, je nachdem, wie Tcl/Tk auf Ihrem System installiert ist. Die Funktionen, die wir im Folgenden hinzu fügen, sind im Kasten “Die Funktionen von povgui” zusammen gestellt.

Die Funktionen von <I>povgui<I>

  • Bei einem Mausklick auf den Menüpunkt Datei-Szenendatei soll
  • ein Dateibrowser erscheinen, in dem die Datei mit der Szenenbeschreibung ausgewählt werden kann.
  • povgui aus dem Dateinamen der Szenendatei einen Vorschlag für den Namen der von Povray zu erzeugenden Bilddatei erstellen, der dann im Eingabefeld Bildname erscheint.
  • Klickt man auf den Button Rendern, so soll
  • Povray mit den Namen der Szenen- und Bilddateien sowie Angaben zur Bildgeometrie aufgerufen werden.
  • Wird der Button Anzeigen mit der Maus aktiviert, soll
  • das gerenderte Bild von einem Bildbetrachtungsprogramm angezeigt werden.
  • Mit den Schiebereglern für Bildbreite und Bildhöhe soll
  • die Geometrie des zu rendernden Bilds eingestellt werden können.
  • Im Eingabefeld Bildname soll
  • der Vorschlag von povgui für den Namen der Bilddatei angezeigt werden und
  • dieser vom Benutzer geändert werden können.

In dieser Aufzählung sind auch schon die benötigten Variablen erkennbar:

  • der Name der Szenendatei,
  • der Name der Bilddatei,
  • die Breite und
  • die Höhe des Bilds.Genau diese Variablen wurden bereits im zweiten Artikel [8,9] benötigt, doch diesmal werden sie – etwas eleganter – in einem Array organisiert.

Arrays

Unter Feldern oder Arrays versteht man Zusammenstellungen von Variablen unter einem einheitlichen Namen. Sie bestehen aus dem Array-Namen und dem Namen der jeweiligen Elemente, wobei jedes Array-Element eine Variable ist.

Im Gegensatz zu anderen Programmiersprachen, bei denen Elementbezeichner als fortlaufender Index dienen und daher natürliche Zahlen sein müssen, können in Tcl/Tk beliebige Zeichenketten als Namen für Elemente verwendet werden. Diese werden in runde Klammern eingeschlossen an den Arraynamen angehängt. (Leerzeichen in Elementnamen gelten als Zeichen!)

Um sich das Konzept klarer zu machen, halten Sie am Besten eine kleine Zwiesprache mit Ihrem Interpreter. Starten Sie dazu die wish in einem X-Terminal.

Nun können Sie z.B. ein Array arbeitszeit anlegen, in dem Sie für jeden Wochentag die von Ihnen geleistete Arbeitszeit speichern. Bei der Definition eines ersten Array-Elements wird gleichzeitig auch das Array selbst erzeugt.

billi@ratschni > wish
% # Definition des Arrays
% # und des Elements montag
% set arbeitszeit(montag) 6
6
% # Definition des Elements dienstag
% set arbeitszeit(dienstag) 9
9
% # Ausgabe der Arbeitszeit vom Montag
% puts "Am Montag habe ich $arbeitszeit(montag) Stunden gearbeitet"
Am Montag habe ich 6 Stunden gearbeitet
% exit
billi@ratschni >

Die Zeilen mit einem Gatter (#) am Anfang sind übrigens Kommentarzeilen und dienen nur zur Erläuterung; der Interpreter “übersieht” sie.

Für das Povray-Interface ist es sinnvoll, ein Array mit dem Namen pov o.ä. anzulegen, in dem die benötigten Variablen als Array-Elemente unter gebracht werden. Die Variablen für Bildhöhe und Bildbreite können Sie bei dieser Gelegenheit schon mal mit einem Vorgabewert versehen (Zeile 6–9 in Listing 1):

set pov(szene)  ""
set pov(bild)   ""
set pov(breite) 400
set pov(hoehe)  200

Drei dieser Variablen lassen sich direkt mit den Widgets verknüpfen, mit deren Hilfe die Benutzer die darin abgelegten Werte ändern können:

  • pov(bild) mit dem Eingabefeld,
  • pov(breite) mit dem Breitenregler und
  • pov(hoehe) mit der Höhenregler.

Ein Eingabefeld (entry) kann mit der Option -textvariable name_der_variablen (Zeile 74) versehen werden. Jeder Wert, den name_der_variablen annimmt, wird dann im Eingabefeld dargestellt. Umgekehrt bekommt die Variable auch den Wert, den der Benutzer im Eingabefeld eingibt.

Schieberegler (scale) kennen die Option -variable name_der_variablen (Zeile 76 und 78). Auch hier beeinflussen sich die Stellung des Reglers und der Wert der Variablen gegenseitig. Ändert sich der Variableninhalt, so bewegt sich der Regler wie von Geisterhand auf den neuen Wert. Wird der Regler verschoben, ändert sich auch der Variablenwert.

Nun können Sie auch den Anzeigen-Button aus Abbildung 1 mit einem Kommando beglücken. Er soll den Bildbetrachter xv samt dem Namen der Bilddatei aufrufen. Da es sich dabei um den Aufruf eines externen Unix-Programms handelt, muss diesem ein exec voran gehen. Um das Interface nicht so lange zu blockieren, wie xv läuft, wird der Befehl durch ein hintangestelltes Kaufmannsund (&) im Hintergrund gestartet. Der komplette Befehl lautet somit exec xv $pov(bild) & (Zeile 49).

Ähnlich können Sie nun das Kommando zum Zusammenstellen der povray-Befehlszeile an den Rendern-Button anknüpfen (Zeile 45 und 46):

exec povray +I$pov(szene) +O$pov(bild) +W$pov(width) +H$pov(height) &

Wenn Sie sich nun dem letzten zu versorgenden Widget, dem Menüpunkt Szenendatei wählen … im Menü des Datei-Menübuttons, zuwenden, stellen Sie fest, dass dieser bei einem Mausklick ziemlich viele Dinge zu tun hat. Er muss einen Dateimanager öffnen, die darin ausgewählte Datei in der Variablen pov(szene) speichern und den Vorschlag für den Dateinamen der Bilddatei generieren.

Wie die meisten Widgets kennt auch ein Eintrag in einem Pull-Down-Menü die Option -command, mit der Sie den Button Befehle ausführen lassen können. Wenn Sie aber die oben aufgeführten Aktionen in eine -command-Option packen, sieht das höchst unschön aus. Das muss auch nicht sein, denn es gibt in Tcl die Möglichkeit, mehrere Befehle in einer Extra-Sequenz zusammen zu stellen und diese Sequenz als eigenen Befehl aufzurufen. Diese Konstruktion wird Prozedur genannt.

Prozeduren

Eine Tcl/Tk-Prozedur besteht aus vier Teilen und wird mit dem Befehl proc eingeleitet:

proc ProzedurName {eventuelle Argumente} { Rumpf mit den Befehlen }

Durch die Angabe von Argumenten können Sie der Prozedur Variablen mit auf den Weg geben. Falls Sie dies nicht möchten, bleibt die erste Klammer leer, muss aber mit aufgeschrieben werden.

Die im zweiten geschweiften Klammernpaar zusammen gestellten Befehle können Sie durch Angabe des Prozedurnamens ausführen. Falls Sie Argumente definiert haben, müssen diese bei einem Prozeduraufruf immer mit angegeben werden.

Verdeutlichen Sie sich dies am besten durch Interaktion mit dem Interpreter. Bis zur öffnenden Klammer des Prozedurrumpfes muss alles in eine einzige Zeile geschrieben werden. Im Prozedurrumpf selbst können Sie dann beliebig viele Leerzeilen einfügen.

billi@ratschni > wish
% # Definition der Prozedur "schreibe"
% # mit einem Argument: text.
% proc schreibe { text } { puts $text }
%
% # Aufruf der Prozedur mit einem Argument.
% schreibe "Was für ein schöner Tag"
Was für ein schöner Tag
%
% # Ohne Argument läuft nix.
% schreibe
no value given for parameter "text" to "schreibe"
%
% # Neudefinition von "schreibe",
% # diesmal mit zwei Argumenten.
% proc schreibe { text1 text2 } {puts $text1puts $text2}
%
% # Erneuter Aufruf
% schreibe "Das Leben" "ist schön"
Das Leben
ist schön
% exit
billi@ratschni >

Variablen innerhalb einer Prozedur haben eine Besonderheit: Sie sind nur innerhalb der Prozedur – also lokal – vorhanden:

billi@ratschni > wish
% # Definition der Prozedur "versteckt"
% proc versteckt { } { set gruss Ciao }
%
% # Setzen des gruss-Inhalts
% # ausserhalb der Prozedur.
% set gruss Hallo
Hallo
%
% # Aufruf der Prozedur
% # zum Aendern des grusses
% versteckt
%
% # Aber gruss bleibt gruss...
% puts $gruss
Hallo
% exit
billi@ratschni >

Die Variable gruss innerhalb der Prozedur versteckt und die außerhalb der Prozedur definierte Variable mit dem selben Namen sind unterschiedliche Variablen, die nichts von einander wissen und sich gegenseitig nicht beeinflussen.

Die Möglichkeit, inner- und außerhalb einer Prozedur auf die gleiche Variable zuzugreifen, hat man, wenn die Variable als global definiert ist:

billi@ratschni > wish
% proc sichtbar { } {global grussset gruss Ciao}
%
% # Definition von gruss
% # ausserhalb der Prozedur.
% set gruss Hallo
Hallo
%
% # Aufruf der Prozedur
% # zum Aendern des grusses
% sichtbar
%
% # Jetzt hat sich der gruss geandert
% puts $gruss
Ciao
% exit
billi@ratschni >

Mit diesem Wissen gerüstet, können Sie nun eine Prozedur anlegen, die Sie mit dem Menübutton verknüpfen und – da sie ja im Wesentlichen für die Auswahl einer Datei zuständig sein wird – dateiAuswahl nennen. Innerhalb dieser Prozedur müssen Sie das Array pov als global deklarieren, damit Sie von Innen wie Außen auf die selben Variablen zugreifen.

proc dateiAuswahl { } {
    global pov
    # Anstelle dieses Kommentars
    # kommen gleich die Befehle
}

Dateibrowser

Einer der meiner Meinung nach schönsten Tcl/Tk-Befehle ist der zum Aufruf eines Dateimanagers. Das geht ganz einfach mit tk_getOpenFile. Wenn Sie nur bestimmte Dateien angezeigt bekommen möchten, erweitern Sie diesen Befehl um die Option -filetypes und geben danach die Art der anzuzeigenden Dateien und deren Endung an. Dabei sind prinzipiell mehrere Kombinationen aus Dokumentenart und -endung möglich. Daher muss jede einzelne Kombination in extra Klammern zusammen gefasst und alle gemeinsam noch einmal in Klammern eingeschlossen werden. Diese Doppel-Klammer-Technik bleibt Ihnen auch dann nicht erspart, wenn Sie nur eine einzige Dokumentenart-Endung-Kombination angeben.

Im Fall des Povray-Interfaces handelt es sich um Povray-Dokumente mit der Endung .pov. Der komplette Befehl lautet damit:

tk_getOpenFile -filetypes { { Povray-Dokumente .pov } }

Wenn Sie diesen Befehl im Interpreter testen, sieht das Ergebnis aus wie in Abbildung 2 – natürlich mit anderen Verzeichnisnamen und abweichendem Verzeichnisinhalt.

Abbildung 2: Tcl/Tks Dateibrowser

Abbildung 2: Tcl/Tks Dateibrowser

Zurück gibt tk_getOpenFile den Namen der ausgewählten Datei. Wenn Sie den Befehl in eckigen Klammern aufrufen, werden die Klammern nebst Inhalt durch das Ergebnis des Befehls ersetzt. Dieses können Sie dann in der Variablen pov(bild) speichern und in den Namen der Bilddatei umwandeln.

Dazu verwenden Sie wie in Teil zwei dieser Einführung den Befehl file mit dem Argument rootname und einem Dateinamen. Auf diese Art entfernen Sie die Dateiendung und können eine neue Dateinamenserweiterung anhängen (Zeile 20–30):

proc dateiAuswahl { } {
    global pov
    # Oeffnen des Dateibrowsers
    set pov(szene) [ tk_getOpenFile \
        -filetypes { { Povray-Dokumente .pov } }
                    ]
    # Erstellen des Namens für die Bilddatei
    set pov(bild) [ file rootname $pov(szene) ]
    set pov(bild) $pov(bild).tga
}

Damit wäre Ihr Programm fertig. Sie glauben nicht, dass das so schnell ging? Nun, dieses Interface ist noch nicht perfekt, da es hauptsächlich zum Erklären von Tcl/Tk entstand. Es könnte z.B. wie in [8] noch die Möglichkeit bieten, die Geometrie nur auf Wunsch einzustellen, oder zusätzlich einen Button zum Starten des Editors besitzen.

Doch nach der Lektüre dieser Einführung sind Sie sicher in der Lage, alles besser zu machen und povgui Ihren Wünschen entsprechend anzupassen.

Listing 1

povguis Oberfläche

Im Folgenden sehen Sie das Arbeitsergebnis unserer vierteiligen Einführung in Tcl/Tk – ein Progrämmchen mit grafischer Oberfläche, mit dem sich der Raytracer PovRay leichter bedienen lässt. Der Quelltext ist durchnummeriert, um das Abschreiben – ohne Zeilennummern – zu erleichtern; im vierten Teil neu hinzu gekommenen und daher im vorliegenden Artikel beschriebenen Code erkennen Sie am Fettdruck.

1 #!/bin/sh
 2 #\
 3 exec wish "$0"
 4
 5 ########## Variablendefinition ########## 
 6 set pov(szene) "" 
 7 set pov(bild) "" 
 8 set pov(breite) 400 
 9 set pov(hoehe) 200 
10 
11  
12 ########## dateiAuswahl ########## 
13 # Ermittelt den Namen der Szenendatei 
14 # und erstellt daraus den Namen der zu rendernden Datei 
15 # 
16 # Variablen: 
17 # datei(szene): Name der Szenendatei 
18 # datei(bild) : Name der zu rendernden Datei 
19  
20 proc dateiAuswahl { } { 
21  global pov 
22  
23  # Oeffnen des Dateibrowsers 
24  set pov(szene) [ tk_getOpenFile \ 
25  -filetypes { { Povray-Dokumente .pov } } 
26  ]
27  # Erstellen des Namens für die Bilddatei 
28  set pov(bild) [ file rootname $pov(szene) ] 
29  set pov(bild) $pov(bild).tga 
30 } 
31  
32 ########## Fensterelemente ########## 
33
34 # Die Frames, in denen die anderen Widgets angeordnet werden:
35 frame .obererRahmen    -borderwidth 1 -relief raised
36 frame .mittlererRahmen -borderwidth 1 -relief raised
37 frame .untererRahmen   -borderwidth 1 -relief raised
38
39 pack .obererRahmen    -side top -fill x
40 pack .mittlererRahmen -side top -fill x
41 pack .untererRahmen   -side top -fill x
42
43 # Die Buttons in der unteren Zeile:
44 button .renderKnopf  -text Rendern \ 
45       -command { exec povray +I$pov(szene) +O$pov(bild) \ 
46       +W$pov(width) +H$pov(height) & } 
47
48 button .anzeigeKnopf -text Anzeigen \ 
49       -command { exec xv $pov(bild) & } 
50
51 pack .renderKnopf  -in .untererRahmen \
52       -side left -fill x -expand yes
53 pack .anzeigeKnopf -in .untererRahmen \
54       -side left -fill x -expand yes
55
56 # Der Menuebutton mit Menue:
57 menubutton .dateiKnopf -text Datei -menu .dateiKnopf.herunterklappMenue
58
59 menu .dateiKnopf.herunterklappMenue
60 .dateiKnopf.herunterklappMenue add command -label "Szenendatei wählen ..."  \
61       -command dateiAuswahl
62 .dateiKnopf.herunterklappMenue add separator
63 .dateiKnopf.herunterklappMenue add command -label "Beenden" -command exit
64
65 pack .dateiKnopf -in .obererRahmen -side left
66
67 # Die Beschriftung für Eingabefeld und Schieberegler:
68 label .bildnameAufschrift   -text Bildname
69 label .bildbreiteAufschrift -text Bildbreite
70 label .bildhoeheAufschrift  -text Bildhöhe
71
72 # Eingabefeld und Schieberegler:
73 entry .bildnameEingabefeld -width 30 \ 
74       -textvariable pov(bild)
75 scale .bildbreiteScale -from 20 -to 400 -orient horizontal \ 
76       -variable pov(width)
77 scale .bildhoeheScale  -from 20 -to 400 -orient horizontal \ 
78       -variable pov(height)
79
80 # Anordnen der Widgets im mittleren Teil:
81 grid .bildnameAufschrift   -in .mittlererRahmen -row 0 -column 0 -sticky sw
82 grid .bildbreiteAufschrift -in .mittlererRahmen -row 1 -column 0 -sticky sw
83 grid .bildhoeheAufschrift  -in .mittlererRahmen -row 2 -column 0 -sticky sw
84 grid .bildnameEingabefeld  -in .mittlererRahmen -row 0 -column 1 -sticky we
85 grid .bildbreiteScale      -in .mittlererRahmen -row 1 -column 1 -sticky we
86 grid .bildhoeheScale       -in .mittlererRahmen -row 2 -column 1 -sticky we
87
88 # Aendern des Fenstertitels:
89 wm title . "povgui"

Glossar

Povray

Ein Bilderzeugungsprogramm, das aus mathematischen Daten Bilder berechnet (“rendert”). Die Oberflächenfarbe der Objekte einer Szene ermittelt es durch Zurückverfolgen der auftreffenden Lichtstrahlen (daher Raytracer – “Strahlenverfolger”).

Interpreter

Eine der Möglichkeiten, dem Rechner Quelltexte (also von Programmiererinnen geschriebenen Programmcode) verständlich zu machen. Der Interpreter nimmt sich des Quellcodes an und übersetzt ihn während der Programmausführung für den Computer. Der Interpreter der Skriptsprache Tcl heißt tclsh. Will man zudem Tk, die passende Bibliothek zum Erzeugen der Fensterelementen, nutzen, benötigt man an seiner Stelle die “Windowing Shell” wish.

Widgets

Abgeleitet von “window” und “gadget” (“Dingsbums”) bezeichnet der Begriff Widget Fensterelemente wie z.B. Buttons, Schieberegler und Eingabefelder.

\

Da ein Zeilenumbruch in Tcl/Tk immer auch ein Befehlsende ist, muss ein Zeilenwechsel innerhalb eines Befehls maskiert werden. Dies geschieht durch einen Backslash (\). Nach diesem darf allerdings außer der Enter-Taste kein Zeichen mehr eingetippt werden – auch ein Leerzeichen führt zu einer Fehlermeldung.

Infos

[1] Eine gute Einführung in Povray ist von Christian Perle im Linux-Magazin 04/1998 erschienen. Sie ist auch im WWW erhältlich: http://www.linux-magazin.de/ausgabe/1998/04/Povray/povray.html

[2] Falls Sie Povray noch nicht haben, bekommen Sie es hier: http://www.povray.org/

[3] Tcl/Tk ist zwar bei jeder Distribution dabei, im Source-Code können Sie es aber auch herunter laden bei: http://www.scriptics.com/home.html

[4] John Ousterhout, der “Erfinder” von Tcl/Tk, hat selbst ein sehr lesenswertes Buch geschrieben: Ousterhout, John K.: “Tcl und Tk”, Addison-Wesley, Bonn 1995

[5] Wenn Sie schon über Tcl/Tk-Grundkenntnisse verfügen, die Sie auf sinnvolle Weise vertiefen möchten, ist folgendes Buch zu empfehlen: Harrison, Mark und McLennan, Michael: “Effektiv Tcl/Tk programmieren”, Addison-Wesley, Bonn 1998

[6] Online-Infos bekommen Sie unter anderem bei: http://www.sco.com/Technology/tcl/Tcl.html

[] Der erste Teil dieser Programmiereinführung ist erschienen im: [7a] Linux-Magazin 04/2000, S. 120–124 und online abrufbar unter: [7b] http://www.linux-user.de/ausgabe/2000/06/TclTk1/tcl1.html

[8] Teil zwei können Sie nachlesen im: Linux-Magazin 06/2000, S. 148–153

[9] Linux-User 06/2000, S. 78–83

[9] Linux-Magazin 08/2000, S. 116–122

[10] Linux-User 08/2000, S. 30–36

LinuxUser 10/2000 KAUFEN
EINZELNE AUSGABE
ABONNEMENTS
TABLET & SMARTPHONE APPS
E-Mail Benachrichtigung
Benachrichtige mich zu:

Hinweis: Dieser Artikel ist älter als ein Jahr, enthaltene Informationen sind möglicherweise veraltet.

0 Kommentare
Älteste
Neuste Beste Bewertung
Inline Feedbacks
Alle Kommentare anzeigen
Nach oben