Unertwartete Exception bei Tk-Programm

Fragen zu Tkinter.
Antworten
Markus12
User
Beiträge: 195
Registriert: Dienstag 6. März 2007, 19:32
Wohnort: Frankfurt am Main

Hallo zusammen,
Habe mir überlegt mich am Spiel "Pong" zu probieren und bin gerade dabei erstmal die beiden Balken von einander unabhängig bewegbar zu machen. Dafür habe ich Threads verwendet.
Beim Bewegen eines der beiden Balken kommt es allerdings immer zu einer Exception, sobald ich ein Stück mit dem Balken entweder hoch oder runter gescrollt habe. Die Exception kann ich leider nicht genau interpretieren, da man Exceptions bekanntlich nicht so einfach in Threads gesagt bekommt, da hängt sich das ganze Teil normalerweise erstmal schön komplett auf :)
Deswegen habe ich es mit der try-Anweisung printen lassen:

Code: Alles auswählen

(<class 'ValueError'>, ValueError('could not convert string to float: expected',), <traceback object at 0x01378350>)
Ich vermute, dass der Fehler beim Canvas hängt... Zeile im Programm kann ich mit meiner Methode leider nicht orten.

Bei Bewegen beider Balken und auftretenden Exceptions bei beiden stellt das Betriebssystem außerdem schnell einen Fehler in pythonw.exe fest und beendet python.

Ich mag Threads generell nicht, da hat man nur Ärger :roll:

Kennt jemand eine andere Angehensweise den Fehler zu beheben oder erstmal zu orten? :)

Ausgelagerter Python-Code: http://paste.pocoo.org/show/129014/

Viele Grüße Markus :)
PS: Danke im Voraus
BlackJack

Ohne jetzt in den Quelltext reingeschaut zu haben: Threads und GUIs vertragen sich nicht so einfach. Man darf in der Regel nur aus dem Thread, in dem die Ereignisschleife der GUI läuft auf GUI-Elemente zugreifen, oder man muss entsprechende Sperrmassnahmen ergreifen, wenn das GUI-Toolkit so etwas bietet.

Bei Tkinter wird meistens zur `after()`-Methode auf Widgets geraten.
Markus12
User
Beiträge: 195
Registriert: Dienstag 6. März 2007, 19:32
Wohnort: Frankfurt am Main

Hallo Blackjack :)
Das habe ich schon öfters lernen müssen und wurde mir vor einiger Zeit auch mal gesagt. Allerdings dachte ich, dass das sich mit Canvas anders verhalten würde... Und vorallem jetzt, wo es fast problemlos läuft, erhärtete sich dieser Verdacht. Bei anderen tkinter Sachen hängt sich der Thread normalerweise komplett auf, mhhh.
Achso, auch habe ich gestern erst eine Klasse geschrieben, die von threading.Thread erbt und einen Ball zeichnet, der sich auf einem Canvas bewegt und beim Anstoßen am Rand des Canvases abprallt. Da läuft es fehlerfrei, ohne exception, was ich dann auch komisch finde.

Falls es jemand ausprobieren möchte, habe ich es hier hochgeladen:
http://paste.pocoo.org/show/129045/

Ich bin verwirrt, werde es aber auf deinen Hinweis hin nun mit after versuchen, hoffentlich bringt mich das weiter ;)

Danke!

Grüße Markus :)
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Noch ein paar Tips zu deinem Code:

- Entferne die *-Importe, die müllen Dir nur den ganzen Namensraum voll. Nutze als Ersatz einfach "import Tkinter" oder "import Tkinter as tk" und greife auf das Modul dann qualifiziert (Tkinter.Label, bzw. tk.Label) zu.
- Wenn du Namen durchnummerierst, solltest du über Tupel oder Listen nachdenken. In deinem Fall würde sich für die Koordinaten ersteres anbieten.
- Warum heißt es "_beenden" und nicht "beenden"? Man kann die Variable problemlos benutzen, ohne das man mit irgendwelchen Nebenwirkungen rechnen müsste. Da es sich um einen Thread handelt, wären andere Mechanismen zu Beenden aber besser angebracht (Lock).
- Den noch einmal über die innere while-Schleife in der run-Methode nach. Da lässt sich noch was machen. Außerdem ist sie viel zu lang (länger als 79 Zeichen).
- Ein sleep von 0.005 entspricht 200 Durchläufen pro Sekunde. Das treibt wahrscheinlich die Auslastung ein wenig in die Höhe und liegt deutlich über dem, was dein Monitor anzeigen kann. Außerdem hält wohl kein Timer diese Genauigkeit ein.
- Du solltest Konstanten nutzen
Das Leben ist wie ein Tennisball.
Markus12
User
Beiträge: 195
Registriert: Dienstag 6. März 2007, 19:32
Wohnort: Frankfurt am Main

Hallo EyDu,
Danke für deine Tipps!
Auf welches Skript beziehst du allerdings deine Vorschläge? Das Skript meines ersten Posts?

- Meinst du Konstanten wie Klassenvariablen, die noch vor dem Initialisieren definiert werden?
- Wegen dem Namen durchnummerieren, meinst du Sachen wie

Code: Alles auswählen

x1, y1, x2, y2 = self.canvas.coords(1)
? In dem Fall fand ich es so sinnvoll, da ich je Koordinate einzeln verwende und ich da keinen Sinn sehe das mit soetwas zu ersetzen:

Code: Alles auswählen

coords = self.canvas.coords(1)
, da in der while-Schleife das dann auch so aussehen müsste:

Code: Alles auswählen

while (coords[0]+velo_x) > 0
...

Grüße Markus :)
Markus12
User
Beiträge: 195
Registriert: Dienstag 6. März 2007, 19:32
Wohnort: Frankfurt am Main

Habe eben auch noch mal den einen Sternimport weggemacht und es so gemacht, wie du sagtest. Hübsches Ergebnis beim Ausführen des Skripts:
Anstatt mir etwas zu printen, wenn es den schon gekannten Fehler gibt, bekomme ich nun eine Unhandled Exception, die so aber überhaupt nicht auftreten dürfte, da ich sie mit try abfange.
Und da soll man Python noch verstehen :?
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Markus12 hat geschrieben:Und da soll man Python noch verstehen :?
Wenn du den Code nicht postest, wird es wohl ein Mysterium bleiben.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Markus12
User
Beiträge: 195
Registriert: Dienstag 6. März 2007, 19:32
Wohnort: Frankfurt am Main

Das habe ich bereits ;) Ich habe nur die Importanweisung geändert, das sollte doch schnell gemacht sein :P
Trotzdem nochmal hier der Code: http://paste.pocoo.org/show/129171/ :wink:
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

Bei mir sieht es so aus:

- Mit Python 3.0 läuft es, zumindest lässt sich der rechte Balken über die Tastatur steuern und es gibt keine Fehlermeldung.

- Mit Python 3.1 läuft es nicht. Im traceback wird Zeile 43 bemängelt: "_tkinter.TclError: out of stack space (infinite loop?)" - Danach kommt noch ein Hinweis darauf, dass du sys importieren musst, wenn du sys.exc_info() aufrufen willst ...
Markus12
User
Beiträge: 195
Registriert: Dienstag 6. März 2007, 19:32
Wohnort: Frankfurt am Main

Stimt, bei alten Versionen dachte ich mir schon, warum man mit sys arbeiten kann, obwohl ich es nicht importiert habe!? Habe try nun sowieso herausgenommen, weshalb ich sys nicht einbauen werde.

Danke dir!
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

Hallo Markus12

Hier wirft dein Code-Snippet auch unter Python3.0 die von numerix erwähnten Exceptions. Die Exception _tkinter.TclError: out of stack space (infinite loop?) entsteht aus dem Grund wie BlackJack schon andeutete in:
http://www.python-forum.de/post-142112.html#142112

Diese Exception ist Systemabhängig und verhält sich von PC-System zu PC-System anderst (eine Art 'Russisches Roulette') Da musst du den Einsatz von 'threading' überdenken.

Gruss wuf :wink:
Take it easy Mates!
Markus12
User
Beiträge: 195
Registriert: Dienstag 6. März 2007, 19:32
Wohnort: Frankfurt am Main

Hallo!
Danke. Habe bereits vor Stunden alles auf "after" umgeschrieben, hier habe ich es nun gepostet: http://paste.pocoo.org/show/129196/
Läuft fehlerfrei und flüssig. Wer sich fragt, warum ich so ein komisches Wirrwar in der handler-funktion gemacht habe; Hat man beim Bewegen des Balken aus Versehen den anderen Button noch nicht losgelassen gehabt, den Button in die entgegengesetzte Richtung aber bereits gedrückt, dann ist der Balken vor und zurück gesprungen, bis man beide Buttons losgelassen hat. Nun damit behoben.

Allerdings hängt der Balken dann auch für manchmal 1-2 Sekunden, was ich wiederum nicht verstehe...

Danke an alle!
Grüße Markus :)
Zuletzt geändert von Markus12 am Samstag 18. Juli 2009, 14:45, insgesamt 1-mal geändert.
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

Hallo Markus12

Super! Jetzt läuft dein Pong-Code-Snippet auch bei mir ohne eine Exception auszulösen.

Gruss wuf :wink:
Take it easy Mates!
Antworten