Seite 1 von 1
Unertwartete Exception bei Tk-Programm
Verfasst: Donnerstag 16. Juli 2009, 19:13
von Markus12
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
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
Verfasst: Donnerstag 16. Juli 2009, 19:21
von 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.
Verfasst: Donnerstag 16. Juli 2009, 22:35
von Markus12
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

Verfasst: Donnerstag 16. Juli 2009, 22:49
von EyDu
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
Verfasst: Freitag 17. Juli 2009, 15:17
von Markus12
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
? 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:
, da in der while-Schleife das dann auch so aussehen müsste:
...
Grüße Markus

Verfasst: Freitag 17. Juli 2009, 16:32
von Markus12
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

Verfasst: Freitag 17. Juli 2009, 16:45
von Leonidas
Markus12 hat geschrieben:Und da soll man Python noch verstehen

Wenn du den Code nicht postest, wird es wohl ein Mysterium bleiben.
Verfasst: Freitag 17. Juli 2009, 17:16
von Markus12
Das habe ich bereits

Ich habe nur die Importanweisung geändert, das sollte doch schnell gemacht sein

Trotzdem nochmal hier der Code:
http://paste.pocoo.org/show/129171/ 
Verfasst: Freitag 17. Juli 2009, 17:41
von numerix
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 ...
Verfasst: Freitag 17. Juli 2009, 17:47
von Markus12
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!
Verfasst: Freitag 17. Juli 2009, 18:10
von wuf
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

Verfasst: Freitag 17. Juli 2009, 19:19
von Markus12
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

Verfasst: Freitag 17. Juli 2009, 20:31
von wuf
Hallo Markus12
Super! Jetzt läuft dein Pong-Code-Snippet auch bei mir ohne eine Exception auszulösen.
Gruss wuf
