Theorie: Dialoge & Popup-Menüs

Ein Popup-Menü öffnet sich, wenn man beispielsweise in einem Text-Widget auf die rechte oder linke Maustaste drückt. Wichtig: Das Menü öffnet sich gerade an der Stelle, an der sich der Mauszeiger befindet. Dies bedeutet: Dem Popup- Menü muss irgendwie mitgeteilt werden, an welcher Position es sich öffnen soll. Ein Beispiel (siehe popup.py):

from tkinter import *            ## Tkinter importieren

## Eventhandler, liefert Maus-Koordinaten
def popupMenu(event):
    popup.post(event.x_root, event.y_root)

root = Tk()        ## Toplevel-Widget

foben = Frame(root,width=500)         ## Frame
foben.pack(expand=YES, fill=BOTH)

textfenster = Text(foben,width=90)        ## Textfenster
textfenster.pack(fill=BOTH,expand=YES)

popup = Menu(foben,tearoff=0)        ## Popup-Menue
popup.add_command(label='Info', command=info)
popup.add_separator()
popup.add_command(label='Beenden', command=ende)

## Maustaste an Event-Methode binden
textfenster.bind('<Button-3>',popupMenu)

Ergebnis:

Das Popup-Menü wird wie ein ganz normales Menü vereinbart: popup = Menu(foben,tearoff=0)


Dialoge

Dialog-Fenster sind überraschend schwer zu programmieren! Warum ist das so? Erstens hat man es mit zwei Fenstern zu tun, wobei das Schließen des Dialog-Fensters nicht gleich die ganze Tkinter-Anwendung beenden darf. Zweitens findet normalerweise irgendein Datenaustausch zwischen dem Dialog-Fenster und dem Tkinter-Skript statt, man braucht also (Tkinter-)Variablen, die dann nach Beenden des Dialogs ausgelesen werden. Beispiel:

Dieser Dialog wird aufgerufen im Skript dialog.py. Wir betreten hier endgültig das weite Feld der objektorientierten Programmierung: Fenster und Buttons sind eben Objekte mit bestimmten Eigenschaften und Verhaltensweisen, sprich Methoden. Man fasst das Verhalten dieser Objekte in Klassen zusammen, und eine konkrete Instanz dieser Klasse ergibt dann ein Objekt (dieser Klasse). Beispiel: Es gibt die Text-Widget-Klasse, und ein konkretes Textfenster vereinbaren wir so:

textfenster = Text()

textfenster ist hier der Name des Objektes, über den wir Zugriff auf die Eigenschaften und Methoden der Klasse Text() haben. Nichts anderes haben wir oben in Teil 3 über Textfenster gemacht. Mit Klassen ist meist ein Modell der Vererbung verbunden. Dies bedeutet, dass Klassen Eigenschaften und Methoden vererben können, die man dann in den Subklassen verändern (Man sagt auch: überschreiben) oder ergänzen kann. Klassen bieten damit ein sehr flexibles Konzept zur Erweiterung der Fensterbibliothek! Eine Erweiterung der Klasse Dialog ist die Klasse simpledialog, dieses Modul gehört zum Standardumfang von Python's Tkinter Bibliothek. Wir überschreiben in unserer Anwendung die folgenden beiden Methoden der Dialog-Klasse:

body(self, master)

apply(self)

Die Klassendefinition DialogFenster "steht", wie aber wird sie benutzt? Dazu muss ein Objekt ins "Leben" gerufen werden. Im Skript dialog.py gibt es hierzu die Methode benutzer(), die als Aktion einem Eintrag im Popup-Menü zugeordnet ist (command=benutzer). In der Methode benutzer() wird zuerst unser Dialogfenster ins "Leben" gerufen, dann wird die Flag-Variable result getestet, und schließlich wird der Inhalt der Eingabezeile des Dialogfensters im Textfenster (& in einer Message-Box) ausgegeben:

def benutzer():
    NamenDialog = DialogFenster(root)
    if NamenDialog.result <> None:
        textfenster.insert(END,'Hallo, ' + NamenDialog.a1 + '!\n')
        messagebox.showinfo('Dialog-Fenster','Hallo, ' + NamenDialog.a1 + '!')

Aufgaben

  1. Ergänze das Popup-Menü im Tkinter-Skript popup.py um einen weiteren Eintrag mit entsprechender callback-Methode (siehe den Abschnitt über's Binding).

  2. In das Skript popup.py ist eine Python-Test-Version eingebaut, sie testet um welche Python-Version es sich handelt. Wo befindet sich dieser Programm-Teil, und weshalb ist er notwendig?

  3. Jetzt bauen wir unser eigenes Dialog-Fenster: Erweitere dein Skript aus Aufgabe 1 um die notwendigen Teile für ein Dialogfenster mit zwei Labels (!) und zwei Eingabezeilen (!!) (Label 1: 'Login', Label 2: 'Password'). Wo müssen diese Änderungen hinein? Wie kann man die Eingabe in der zweiten Eingabezeile auslesen? Und wie kann man die Eingabe aus dem Dialog-Fenster im Text-Widget anzeigen?
    Bei Fragen untersuche das Skript dialog.py (Dieses Skript enthält keine Lösung der Aufgabe, du kannst aber im Chat-Client nachschauen: im Skript chat_client.py gibt es die Methode einstellungen(), die ein Fenster für die Einstellungen öffnet, beispielsweise für die Einstellung der TCP/IP-Adresse des Servers)


→ sp, 2023-07-28