Vokabeltrainer (mal anders) Ui träge

Fragen zu Tkinter.
Antworten
bmbl
User
Beiträge: 1
Registriert: Sonntag 4. Oktober 2009, 10:19

Ich habe mir einen kleinen Vokabelwiederholer geschrieben der bei mir auf dem Desktop sitzen soll, eine Vokabel anzeigt und ein paar Sekunden später die Übersetzung.

Klappt soweit ganz gut nur, dass das UserInterface sehr träge ist. Ich denke mal deshalb, weil f_loop ausgeführt wird und erst danach wieder input erlaubt/erfasst wird.

Mir ist das Prinzip, das UI in einer Klasse so zu verbauen noch ein wenig neu und wollte mal fragen wie ich es eleganter löse (Ich denke das Problem, dass es nicht reagiert könnte man mit threads lösen?)

Code: http://paste.pocoo.org/show/142815/
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

Blockiere NIEMALS den UI-Thread mit etwas wie sleep!

Benutze `after`, wenn du etwas nach ein paar Sekunden ausführen willst.

Stefan
BlackJack

@bmbl: Du kannst da auch auf diese Weise keine eigene "main loop" haben. Das Programm hat ja schon eine, nämlich die Hauptschleife von `Tkinter`. Die ruft Deinen Quelltext bei bestimmten Ereignissen auf und da kannst Du dann kurz etwas machen. Solange Dein Code läuft, ist die GUI blockiert, dass heisst das sollte nicht lange dauern, was Du da machst. So ein linearer Programmablauf wie bei der Kommunikation mit dem Anwender auf der Textkonsole mit Schleifen oder gar `sleep()` für Wartezeiten, funktioniert bei ereignisbasierter GUI-Programmierung nicht mehr. Die `update()`-Methode musst Du nur aufrufen, weil Du die GUI-Hauptschleife nicht ihren Job erledigen lässt.

Die Namensgebung ist übrigens ziemlich schlecht. Was soll das `f_` vor den Methoden? Warum die Abkürzungen und Durchnummerierung von Namen? Bei dem hier weiss doch kein Mensch was da eigentlich passiert, ohne zu suchen was `btn1` bis `btn3` bedeutet:

Code: Alles auswählen

        self.status = True
        self.btn1.configure(state=DISABLED)
        self.btn2.configure(state=NORMAL)
        self.btn3.configure(state=DISABLED)
So wäre das viel verständlicher, ohne das man die Zuweisung an die Attribute suchen müsste:

Code: Alles auswählen

        self.running = True
        self.start_button.configure(state=DISABLED)
        self.stop_button.configure(state=NORMAL)
        self.load_button.configure(state=DISABLED)
Warum stecken die Vokabeln in einem Dictionary, das Zahlen von 0 bis Anzahl der Vokabeln minus 1 auf Paare von Zeichenketten abbildet? Das klingt viel eher nach einer Liste. Dann könnte man auch `random.choice()` verwenden um ein Paar auszuwählen.

Ein Objekt sollte in der `__init__()` möglichst komplett initialisiert werden, so dass dort alle Attribute mit sinnvollen Werten vorbelegt werden. Wenn man in anderen Methoden neue Attribute einführt, werden Programme schnell unübersichtlich.

Das Laden ist ziemlich umständlich. Neben der schon erwähnten Liste für die Daten, kann man über die Zeilen einer Datei mit ``for`` iterieren. Und Du erfindest das Rad neu, beziehungsweise die `split()`-Methode auf Zeichenketten. Mit einer "list comprehension" schrumpft die Methdode auf das hier zusammen:

Code: Alles auswählen

    def laden(self):
        lines = open(tkFileDialog.askopenfilename(initialdir='',
                                                  filetypes=[('Text',
                                                              '*.txt')]))
        self.vocab = [line.strip().split('#', 1) for line in lines]
        lines.close()
        self.start_button.configure(state=NORMAL)
Antworten