Tkinter als Klasse - Musterbeispiel

Fragen zu Tkinter.
Antworten
Midori
User
Beiträge: 2
Registriert: Dienstag 21. März 2017, 14:50

Hallo liebes Forum. Nachdem ich mich vor einiger Zeit dazu entschloßen hatte endlich das nachzuholen, was ich schon vor 15 Jahren hätte tun sollen. Und zwar das Programmieren lernen. So seh ich derzeit teilweise den Wald vor leute Bäumen nicht und es fällt mir schwerer als ich es gedacht hätte. Hut ab an alle die das Coden richtig beherrschen.

Nun zu meinem Problem. Ich habe Anfangs aufgrund eines Buches ein wenig mit Pygame gebastelt. Allerdings bin ich dann schnell rüber zu Tkinter um erstmal die Basics zu beherrschon und Spiele waren eh nicht mein Ziel. Und hier tue ich mir gerade noch ein wenig schwer wenn man von Tkinter eine Objekt Klasse erzeugen möchte und wie man das richtig richtig anstellt damit das sauber ist.

Bisher hatte ich das meist nur prozedural?! gestrickt und das lief soweit auch ganz gut. Aber wenn ich das richtig verstehe und der Code sauber sein soll, dann sollte ich das mit OOP angehen und alle programme die ich schreibe imprinzip über if __main__ == '__name__': laufen lassen damit man klassen z.b. später auch importieren kann und der code obendrein sauber zu lesen ist, wenn ich das richtig verstehe. Allerdings bin ich mir noch nicht ganz sicher wie ich dann die Klassen untereinander anspreche, wo die Tkinter Elemente hingehören und wo nicht.

Ich habe jetzt mal den Thread Tkinter Zeichenfeld als Anlass genommen und versucht eine rudimentäre Lösung zu stricken, nur bin mir z.B unsicher ob Bind z.B in der richtigen Funktion liegt. Irgendwie habe ich dir befürchtung das ich da noch etwas ziemlich falsch angehe, kann aber nicht sagen was. Wäre klasse wenn dort mal jemand drüberschauen könnte und mir das auseinandernimmt. :twisted:

Und über einen Link zu einem überschaubarem Beispiel Programm mit Tkinter und was vorbildlich aufzeigt wie das auszusehen hat würde ich mich ebenfalls freuen.

Code: Alles auswählen

import Tkinter as tk

class MainWindow():
    def __init__(self, master):
        self.master = master
        self.frame = tk.Frame(self.master)
        self.frame.pack()
        self.master.title("GUI")
        self.master.geometry("600x600")

        self.canvas = tk.Canvas(self.frame, width=600, height=600, bg="white")
        self.canvas.pack(side="top",expand=True, fill="both")
        
    def draw(self,event):
        x1, y1 = (event.x - 1),(event.y - 1 )
        x2, y2 = (event.x + 1),(event.y + 1)
        self.canvas.create_oval(x1,y1,x2,y2, fill="black")
           
           
def main():
    root = tk.Tk()
    app = MainWindow(root)
    app.canvas.bind("<B1-Motion>", app.draw)
    root.mainloop()
    

if __name__ == '__main__':
    main()           
Zuletzt geändert von Anonymous am Dienstag 21. März 2017, 15:55, insgesamt 1-mal geändert.
Grund: Quelltext in Python-Codebox-Tags gesetzt.
BlackJack

@Midori: Ich würde das `bind()` mit in die `__init__()` packen. Ohne das ist das `MainWindow`-Objekt in diesem Fall nicht sinnvoll nutzbar und ich sehe bei dem Beispiel auch keinen Grund warum das Programm ausserhalb der Klasse diese Verbindung kennen muss.

Ich hätte `MainWindow` wahrscheinlich mindestens von `Frame` abgeleitet, bei dem Namen vielleicht sogar von `Tk`, denn *das* ist ja das Hauptfenster in einem Tk-Programm.
__deets__
User
Beiträge: 14528
Registriert: Mittwoch 14. Oktober 2015, 14:29

BlackJack hat geschrieben: Ich hätte `MainWindow` wahrscheinlich mindestens von `Frame` abgeleitet, bei dem Namen vielleicht sogar von `Tk`, denn *das* ist ja das Hauptfenster in einem Tk-Programm.
Ich halte dagegen: https://en.wikipedia.org/wiki/Compositi ... nheritance - Composition over inheritance.
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

@__deets__: MainWindow ist ein Hauptfenster, oder zumindest ein Frame. Ich sehe hier jetzt keine Komposition.
BlackJack

@__deets__: Was Sirius3 sagt und ich habe ja extra „bei dem Namen“ dazu geschrieben. Alternativ könnte man die Klasse auch in `DrawingApp` oder so umbenennen, aber wenn das Ding Hauptfenster heisst, könnte es auch eines *sein*. „ist-ein(e)“ ist ja genau der Beziehungstyp für Vererbung.
__deets__
User
Beiträge: 14528
Registriert: Mittwoch 14. Oktober 2015, 14:29

MainWindow ist die Klasse, die ein Mainwindow, ggf. mit zusaetzlichem Brimborium, erzeugt und verwaltet. Da sie ihrerseits nicht in einer Widgethierarchie verwandt wird, bei der Vererbung gefordert sein mag, oder man sonst eh alles an Verhalten weiterleiten/nachbilden soll, wuerde ich das auch nicht machen. So wie es zB Qt mit seinen .ui-Dateien auch vorgibt.

Klar kann man das auch noch mal umbenennen in *App in diesem Fall, aber fuer zB einen komplexen Dialog etc. wuerde ich eine solche Klasse trotzdem noch MeinTollerDialog nennen, aber immer noch nicht ableiten.

Und die Gruende sind in meinen Augen hoehere Flexibilitaet. Im Zweifel bekommt die Klasse das Container-Widget als Abhaengigkeit reingereicht, statt sie selbst zu erzeugen, und so wird aus einem frei stehenden Dialog ein Tab innerhalb einer Liste. Wo seht ihr den Vorteil der Vererbung?
BlackJack

@__deets__: Das ist semantisch eben ein Fenster oder zumindest ein Widget. Und zumindest wenn man das Hauptfenster nennt ist es komisch wenn es dann keines *ist*. Qt und *.ui-Dateien können hier IMHO nicht als Begründung herangezogen werden weil das hier nicht Qt ist und die Dinge anders gehandhabt werden.

Die Flexibilität von Komposition wird hier nicht benötigt, also KISS. Man spart sich beim Ableiten von `tk.Frame` den extra `Frame` und hat trotzdem noch die Freiheit das Containerwidget rein zu reichen.
Antworten