Grundsätzlicher Aufbau eines Programms mit mehreren Fenstern

Fragen zu Tkinter.
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

Für das erstellen von Python Skripts würde ich unbeding den Leitfaden PEP 8 anwenden. Sauber ist für mich, wenn ich nach einem Monat noch interpretieren kann was das geschriebene machen sollte. Code lässt sich meistens noch verbessern und verfeinern. OK ich wünsche dir noch viel Spass bei deinem Vorhaben.

Gruß wuf :wink:
Take it easy Mates!
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Also bei der Instanziierung einer Klasse unerwartet eine mainloop zu starten halte ich für alles andere als elegant...
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

Leonidas hat geschrieben:Also bei der Instanziierung einer Klasse unerwartet eine mainloop zu starten halte ich für alles andere als elegant...
Habe ich nicht verstanden?

Gruß wuf :wink:
Take it easy Mates!
deets

Den mainloop() sollte man nicht in App.__init__ aufrufen. Denn das ist sehr ueberraschend - ein Konstruktor sollte ein Objekt zurueckgeben, und nicht unendlich lange laufen.

Besser ist es, eine explizite App.mainloop()-Methode zu machen, die dann an das root-Objekt delegiert.
Scriptinggamer
User
Beiträge: 107
Registriert: Sonntag 24. Juni 2012, 16:38
Wohnort: Werder/Havel

So, der mainloop und das Starten der ersten Frame sind in einer neuen Funktion, ich habe eine main()-Funktion hinzugefügt und alle überflüssigen self's entfernt, das ganze sieht jetzt also so aus:

Code: Alles auswählen

#!/usr/bin/python
# -*- coding: cp1252 -*-

#Module importieren
import tkinter as tk

#Klasse definieren
class App:
    #root/master initialisieren
    def __init__(self, master):
        self.master = master
        self.master.protocol("WM_DELETE_WINDOW", self.quit_app)
        self.master.title("Frames")

    #Hauptfenster initialiesieren und starten
    def mainloop(self):
        self.set_main_frame()
        self.master.mainloop()
        
    #Hauptfenster starten
    def set_main_frame(self):
        #Hauptframe definieren
        self.main_frame = tk.Frame(self.master)
        self.main_frame.pack()
        #Widgets initialisieren
        hallo_label = tk.Label(self.main_frame, text = "Hallo Tkinter!")
        hallo_button = tk.Button(self.main_frame, text = "Weiter", command = self.set_entry_frame)
        quit_button = tk.Button(self.main_frame, text = "Beenden", command = self.quit_app)
        #Widgets positionieren
        hallo_label.grid(row = 0, column = 0, columnspan = 2)
        hallo_button.grid(row = 1, column = 0)
        quit_button.grid(row = 1, column = 1)
        #Bestätigung in der Konsole
        print("Hauptfenster geöffnet")
        
    #Einsellungsfenster starten
    def set_entry_frame(self):
        #Einstellungsframe definieren
        self.entry_frame = tk.Frame(self.master)
        #Hauptframe schließen
        self.main_frame.destroy()
        self.entry_frame.pack()
        #Widgets initialisieren
        head_label = tk.Label(self.entry_frame, text = "Eingaben")
        entry1_label = tk.Label(self.entry_frame, text = "Eingabe 1")
        self.entry1_entry = tk.Entry(self.entry_frame)
        entry2_label = tk.Label(self.entry_frame, text = "Eingabe 2")
        self.entry2_entry = tk.Entry(self.entry_frame)
        safe_entry_button = tk.Button(self.entry_frame, text = "Ausgeben", command = self.set_request_win)
        #Widgets positionieren
        head_label.grid(row = 0, column = 0, columnspan = 2)
        entry1_label.grid(row = 1, column = 0)
        self.entry1_entry.grid(row = 1, column = 1)
        entry2_label.grid(row = 2, column = 0)
        self.entry2_entry.grid(row = 2, column = 1)
        safe_entry_button.grid(row = 3, column = 0, columnspan = 2)
        #Bestätigung in der Konsole
        print("Eingabefenster geöffnet")

    #Bestätigung oder Abbruch
    def set_request_win(self):
        #Eingaben auslesen
        self.entry = [self.entry1_entry.get(), self.entry2_entry.get()]
        #Toplevel Fenster definieren
        self.request_win = tk.Toplevel()
        self.request_win.title("Wirklich?")
        #Widgets initialisieren
        question_label = tk.Label(self.request_win, text = "Möchtest du den Text wirklich ausgeben?")
        agree_button = tk.Button(self.request_win, text = "Also los, gib ihn aus!", command = self.print_entry)
        main_button = tk.Button(self.request_win, text = "Ich überlegs mir...", command = self.to_main)
        quit_button = tk.Button(self.request_win, text = "Sofort alles beenden!", command = self.quit_app)
        #Widgets positionieren
        question_label.grid(row = 0)
        agree_button.grid(row = 1, sticky = "w,e")
        main_button.grid(row = 2, sticky = "w,e")
        quit_button.grid(row = 3, sticky = "w,e")        

    #Eingaben verwerten und zum Hauptfenster zurückkehren
    def print_entry(self):
        ###Eingaben verwerten#########
        for setting in self.entry:   #
            print(setting)           #
        ##############################
        #Nachfragefenster schließen
        self.request_win.destroy()
        #Ausgabeframe schließen
        self.entry_frame.destroy()
        #Hauptframe starten
        self.set_main_frame()

    def to_main(self):
        self.request_win.destroy()
        self.entry_frame.destroy()
        self.set_main_frame()

    def quit_app(self):
        print("Programm beendet")
        self.master.destroy()

#Mainfunktion (ausführen der App)        
def main():
    root = tk.Tk()
    app = App(root)
    app.mainloop()

if __name__ == "__main__":
    main()
Noch weitere Verbesserungsmöglichkeiten? :D
Danke
Gruß
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

Hi Leonidas & deets

Danke für eure Hinweise. Das wusste ich noch nicht. Mein Frage an euch kann ich das folgende Skript als Startvorlage für eine Tkinter-Anwendung verwenden oder sieht ihr da auch bestimmte heikle Punkte?

Code: Alles auswählen

try:
    #~~ For Python 2.x
    import Tkinter as tk
except ImportError:
    #~~ For Python 3.x
    import tkinter as tk

APP_WIN_XPOS = 50
APP_WIN_YPOS = 50

class App(object):
    
    def __init__(self):
        self.win = tk.Tk()
        self.win.geometry('+{0}+{1}'.format(APP_WIN_XPOS, APP_WIN_YPOS))
        self.win.protocol("WM_DELETE_WINDOW", self.close)
    
    def run(self):
        self.win.mainloop()
    
    def close(self):
        self.win.destroy()
            
app = App()
app.win.title("Tk App Templates")

app.run()
Gruß wuf :wink:
Take it easy Mates!
Scriptinggamer
User
Beiträge: 107
Registriert: Sonntag 24. Juni 2012, 16:38
Wohnort: Werder/Havel

Also soweit ich wüsste wäre es ok, aber Leonidas meinte, ich sollte keinen Code auf Modulebene schreiben, also main() funktion und if __name__ == "__main__":
main()
Gruß
Zuletzt geändert von Scriptinggamer am Dienstag 17. Juli 2012, 09:39, insgesamt 1-mal geändert.
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

Hi Scriptinggamer

Hast du den Leitfaden für die Python-Skriptgestaltung näher angeschaut? Er ist unter folgendem Namen bekannt:
-> PEP 8 -- Style Guide for Python Code

Dieser Code-Abschnitt:

Code: Alles auswählen

def set_main_frame(self):
        #Hauptframe definieren
        self.main_frame = tk.Frame(self.master)
        self.main_frame.pack()
        #Widgets initialisieren
        hallo_label = tk.Label(self.main_frame, text = "Hallo Tkinter!")
        hallo_button = tk.Button(self.main_frame, text = "Weiter", command = self.set_entry_frame)
        quit_button = tk.Button(self.main_frame, text = "Beenden", command = self.quit_app)
        #Widgets positionieren
        hallo_label.grid(row = 0, column = 0, columnspan = 2)
        hallo_button.grid(row = 1, column = 0)
        quit_button.grid(row = 1, column = 1)
        #Bestätigung in der Konsole
        print("Hauptfenster geöffnet")
schreibe ich persönlich so:

Code: Alles auswählen

def set_main_frame(self):

    #Hauptframe definieren
    self.main_frame = tk.Frame(self.master)
    self.main_frame.pack()
    
    #Widgets initialisieren
    hallo_label = tk.Label(self.main_frame, text="Hallo Tkinter!")
    hallo_label.grid(row=0, column=0, columnspan=2)
    
    hallo_button = tk.Button(self.main_frame, text="Weiter",
        command=self.set_entry_frame)
    hallo_button.grid(row=1, column=0)
    
    quit_button = tk.Button(self.main_frame, text="Beenden",
        command=self.quit_app)
    quit_button.grid(row=1, column=1)
    
    #Bestätigung in der Konsole
    print("Hauptfenster geöffnet")
Da möchte ich dir aber auf keinen Fall dreinreden wie ich dies bei einem Arzt und seiner Art Rezepte zu schreiben auch nie tun würde. Hi!

Gruß wuf :wink:
Take it easy Mates!
Scriptinggamer
User
Beiträge: 107
Registriert: Sonntag 24. Juni 2012, 16:38
Wohnort: Werder/Havel

Also ich finds um einiges übersichtlicher, die Positionierung in einem Block vorzunehmen, da sind änderungen auch einfacher...
Gruß
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Scriptinggamer hat geschrieben:Also soweit ich wüsste wäre es ok, aber Leonidas meinte, ich sollte keinen Code auf Modulebene schreiben, also main() funktion und if __name__ == "__name__":
main()
Richtig, das sollte man in dieses Beispiel-Skelett einfügen.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Antworten