Tkinter: TclError: bad option "image" - nur mit PyPy...

Fragen zu Tkinter.
Antworten
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Der selbe code läuft mit CPython ohne Probleme, aber mit PyPy kommt das:
Exception in Tkinter callback
Traceback (most recent call last):
File "D:\pypy-2.3.1-win32\lib-python\2.7\lib-tk\Tkinter.py", line 1470, in __call__
return self.func(*args)
File "D:\pypy-2.3.1-win32\lib-python\2.7\lib-tk\Tkinter.py", line 531, in callit
func(*args)
File "V:\workspace\DragonPy\dragonpy\core\gui.py", line 203, in display_queue_interval
self.display.write_byte(cpu_cycles, op_address, address, value)
File "V:\workspace\DragonPy\dragonpy\core\gui.py", line 64, in write_byte
self.render_char(char, color, address)
File "V:\workspace\DragonPy\dragonpy\core\gui.py", line 78, in render_char
anchor=Tkinter.NW # NW == NorthWest
File "D:\pypy-2.3.1-win32\lib-python\2.7\lib-tk\Tkinter.py", line 2260, in create_image
return self._create('image', args, kw)
File "D:\pypy-2.3.1-win32\lib-python\2.7\lib-tk\Tkinter.py", line 2251, in _create
*(args + self._options(cnf, kw))))
File "D:\pypy-2.3.1-win32\lib_pypy\_tkinter\app.py", line 300, in call
self.raiseTclError()
File "D:\pypy-2.3.1-win32\lib_pypy\_tkinter\app.py", line 152, in raiseTclError
raise TclError(tkffi.string(tklib.Tcl_GetStringResult(self.interp)))
TclError: bad option "image": must be addtag, bbox, bind, canvasx, canvasy, cget, configure, coords, create, dchars, delete, dtag, find, focus, gettags, icursor, index, insert, itemcget, itemconfigure, lower, move, postscript, raise, scale, scan, select, type, xview, or yview
Der eigentliche code:

Code: Alles auswählen

        self.canvas.create_image(x, y,
            image=img,
            state="normal",
            anchor=Tkinter.NW  # NW == NorthWest
        )

Allerdings vermute ich das threading hier das eigentliche Problem ist.

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Unter Linux:
Exception NotImplementedError: NotImplementedError('Call from another thread',) in method __del__ of <Tkinter.PhotoImage instance at 0x00007f6f44159880> ignored
:K

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Ich glaube ich mache was falsch.

Ich habe mal einen Test code gemacht: https://gist.github.com/jedie/3a18c659faa70bf10f36

Der ist alleine Lauffähig und ahmt das nach, was im DragonPy Emulator so passiert:
Das sieht so aus:
Bild

Die fakeCPU erzeugt, wie die echte "schreibanweisungen" ins Display RAM. Das wird dann einfach zu Klötzchen mit unterschiedlicher Helligkeit verarbeitet und angezeigt...
Wärend es läuft kann man irgendeine Taste drüben und bekommt eine Log Ausgabe darüber. So kann man sehen, ob es noch gut reagiert.
Über den FAKED_CPU_LOAD kann man festlegen, wie schnell die CPU neue Zeichen ausgibt.

Generell kann man sehen, das mit der Laufzeit es immer langsamer wird.

Ich gehe hin und schreibe immer wieder ein neues Image in den Canvas rein:

Code: Alles auswählen

        self.canvas.create_image(x, y,
            image=img,
            state="normal",
            anchor=Tkinter.NW  # NW == NorthWest
        )
Ich vermute aber, das so, intern immer wieder neue Bilder gespeichert werden. Also quasi das Canvas mit Bilder überfrachtet wird.
Ich sollte also das vorherige Bild an stelle x,y vorher löschen.

Bei create_image() erhält man wohl eine ID des Bildes. Denke mal damit kann ich das dann löschen...

Oder aber, man kann das Bild "austauschen" ?!? Gibt es sowas ähnliches wie self.canvas.overwrite(x,y,img) ?
Wenn ja, dann überlege ich, ob ich nicht einmal den Canvas komplett mit Bilder vollschreibe und dann nur immer tausche.

Vielleicht ist das ganze ja für den Crash zuständig?

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
BlackJack

@jens: Das Canvas ist Vektorgrafik und kein Pixelframe wie bei SDL, da solltest Du tatsächlich nicht immer mehr Elemente übereinanderzeichnen, weil die tatsächlich *alle* immer wieder übereinandergezeichnet werden, auch wenn sie mittlerweile von anderen Elementen vollkommen verdeckt sind.

Beim `create_*()` bekommst Du eine ID zurück über die man das Element später mit `itemconfigure()` ändern kann.
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Ah! Also geht auch ein austauschen.

Gemacht: https://gist.github.com/jedie/3a18c659f ... /revisions ab Zeile 100

Dann mache ich das vielleicht so, das ich erstmal alles mit irgendwas fülle und dann immer nur mir itemconfigure() tausche...

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

So, umgesetzt: https://github.com/jedie/DragonPy/commi ... 314f86a085

Damit ist es schon deutlich stabiler...

Das läuft mit CPython problemlos:

Code: Alles auswählen

10 CLS
20 FOR I = 0 TO 255:
30 POKE 1024+(I*2),I
40 NEXT I
50 GOTO 10
Mach ja das:
Bild

Und das in einer Endlosschleife...

Obwohl es mit PyPy Grundsätzlich auch komplett durch läuft (auch mehrmals) gibt es irgendwann einen Crash, z.B.:

Code: Alles auswählen

Exception in Tkinter callback
Traceback (most recent call last):
  File "D:\pypy-2.3.1-win32\lib-python\2.7\lib-tk\Tkinter.py", line 1470, in __call__
    return self.func(*args)
  File "D:\pypy-2.3.1-win32\lib-python\2.7\lib-tk\Tkinter.py", line 531, in callit
    func(*args)
  File "V:\workspace\DragonPy\dragonpy\core\gui.py", line 227, in display_queue_interval
    self.display.write_byte(cpu_cycles, op_address, address, value)
  File "V:\workspace\DragonPy\dragonpy\core\gui.py", line 83, in write_byte
    image = self.tk_font.get_char(char, color)
  File "V:\workspace\DragonPy\dragonpy\Dragon32\dragon_font.py", line 1260, in get_char
    img.put(color, (x, y))
  File "D:\pypy-2.3.1-win32\lib-python\2.7\lib-tk\Tkinter.py", line 3347, in put
    self.tk.call(args)
  File "D:\pypy-2.3.1-win32\lib_pypy\_tkinter\app.py", line 300, in call
    self.raiseTclError()
  File "D:\pypy-2.3.1-win32\lib_pypy\_tkinter\app.py", line 152, in raiseTclError
    raise TclError(tkffi.string(tklib.Tcl_GetStringResult(self.interp)))
TclError: can't parse color "delete"
"Leerlauf" läuft eine ganze Zeit lange in PyPy. Dabei wird ja, wegen dem Cursor-Blinken auch ständig Bilder auf dem Canvas geändert.

Die Fehler sind auch unterschiedlich:

Code: Alles auswählen

Exception in Tkinter callback
Traceback (most recent call last):
  File "D:\pypy-2.3.1-win32\lib-python\2.7\lib-tk\Tkinter.py", line 1470, in __call__
    return self.func(*args)
  File "D:\pypy-2.3.1-win32\lib-python\2.7\lib-tk\Tkinter.py", line 531, in callit
    func(*args)
  File "V:\workspace\DragonPy\dragonpy\core\gui.py", line 227, in display_queue_interval
    self.display.write_byte(cpu_cycles, op_address, address, value)
  File "V:\workspace\DragonPy\dragonpy\core\gui.py", line 93, in write_byte
    self.canvas.itemconfigure(image_id, image=image)
  File "D:\pypy-2.3.1-win32\lib-python\2.7\lib-tk\Tkinter.py", line 2349, in itemconfigure
    return self._configure(('itemconfigure', tagOrId), cnf, kw)
  File "D:\pypy-2.3.1-win32\lib-python\2.7\lib-tk\Tkinter.py", line 1253, in _configure
    self.tk.call(_flatten((self._w, cmd)) + self._options(cnf))
  File "D:\pypy-2.3.1-win32\lib_pypy\_tkinter\app.py", line 300, in call
    self.raiseTclError()
  File "D:\pypy-2.3.1-win32\lib_pypy\_tkinter\app.py", line 152, in raiseTclError
    raise TclError(tkffi.string(tklib.Tcl_GetStringResult(self.interp)))
TclError: invalid command name "-image"
Ist auch sehr stark unterschiedlich, wann es zu einem crash kommt.

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Antworten