Avoid RecursionError in turtle paint code - python

I'm creating a simple program that uses turtle in a tkinter canvas to allow the user to draw with the mouse. The drawing function seems to work fine however after you draw for a bit the program stops and calls a RecursionError.
from turtle import *
import tkinter as tk
box=tk.Tk()
canv=ScrolledCanvas(box)
canv.pack()
screen=TurtleScreen(canv)
p=RawTurtle(screen)
p.speed(0)
def draw(event):
p.goto(event.x-256,185-event.y) #The numbers are here because otherwise the turtle draws off center. Might be different depending on computer.
canv.bind('<B1-Motion>', draw)
box.mainloop()
This should in theory draw just fine but instead it is calling a RecursionError. I'm lost as to what I can do to prevent this other than maybe wrap the function in a try loop. Any help would be really appreciated.
The output in the Python Shell:
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Program Files (x86)\Python36-32\lib\tkinter\__init__.py", line 1699, in __call__
return self.func(*args)
File "C:\Users\Charlie\Desktop\demo.py", line 17, in draw
p.speed(0)
File "C:\Program Files (x86)\Python36-32\lib\turtle.py", line 2174, in speed
self.pen(speed=speed)
File "C:\Program Files (x86)\Python36-32\lib\turtle.py", line 2459, in pen
self._update()
File "C:\Program Files (x86)\Python36-32\lib\turtle.py", line 2660, in _update
self._update_data()
File "C:\Program Files (x86)\Python36-32\lib\turtle.py", line 2651, in _update_data
self._pencolor, self._pensize)
File "C:\Program Files (x86)\Python36-32\lib\turtle.py", line 545, in _drawline
self.cv.coords(lineitem, *cl)
File "<string>", line 1, in coords
RecursionError: maximum recursion depth exceeded while calling a Python object
I've spent a good deal of time looking around for an answer and as far as I can tell there isn't one anywhere easy to find. This is my first question on this site so please forgive me if something I did was wrong.

I was not able to reproduce your recursion error but I have seen it before. Usually in situations where there are new events coming in while the event handler is busy handling an event. (Which is why it looks like recursion.) The usual fix is to turn off the event handler inside the event handler. Give this a try to see if it works any better for you:
from turtle import RawTurtle, ScrolledCanvas, TurtleScreen
import tkinter as tk
box = tk.Tk()
canv = ScrolledCanvas(box)
canv.pack()
screen = TurtleScreen(canv)
p = RawTurtle(screen)
p.speed('fastest')
def draw(x, y):
p.ondrag(None)
p.setheading(p.towards(x, y))
p.goto(x, y)
p.ondrag(draw)
p.ondrag(draw)
box.mainloop()

Related

easygui buttonbox crashes becase of default font from Tkinter

I'm using easygui in a Python app and then generate an .exe with PyInstaller.
Everything works fine in my computer, but my colleague get this weird error when they try to run the app :
Traceback (most recent call last):
File "easygui\boxes\button_box.py", line 95, in buttonbox
File "easygui\boxes\button_box.py", line 147, in __init__
File "easygui\boxes\button_box.py", line 268, in __init__
File "tkinter\font.py", line 23, in nametofont
File "tkinter\font.py", line 86, in __init__
RuntimeError: main thread is not in main loop
The line where easygui is called is simply
choice = easygui.buttonbox(
"msg", "title", choices=["choice1", "choice2"],
default_choice="choice1", cancel_choice="choice2"
)
so the problem seems to be with the font but I'm not using anything particular in easygui ? I've searched for issues on the easygui's Git but couldn't find anything
Also, there was another easygui.buttonbox earlier in the process but this one did show up properly so I'm just really confused.
Thanks!
The solution was to show the msgbox in the main thread. It crashed because the msgbx was in a different thread than the main one

Why do I get a Terminator error when I run this program?

Here is my code:
import os
from turtle import *
sc = Screen()
sc.setup(600,600)
image = os.path.expanduser("~\OneDrive\Desktop\AlienGameImage.gif")
sc.register_shape(image)
t = Turtle()
t.shape(image)
sc.exitonclick()
Whenever I run this program, the first time it comes up with this error (Error below). However, the second time I run it, it runs fine. Error:
Traceback (most recent call last):
File "C:\Users\hulks\.spyder-py3\untitled0.py", line 14, in <module>
t = Turtle()
File "C:\Users\hulks\anaconda3\lib\turtle.py", line 3813, in __init__
RawTurtle.__init__(self, Turtle._screen,
File "C:\Users\hulks\anaconda3\lib\turtle.py", line 2557, in __init__
self._update()
File "C:\Users\hulks\anaconda3\lib\turtle.py", line 2660, in _update
self._update_data()
File "C:\Users\hulks\anaconda3\lib\turtle.py", line 2646, in _update_data
self.screen._incrementudc()
File "C:\Users\hulks\anaconda3\lib\turtle.py", line 1292, in _incrementudc
raise Terminator
Terminator
The error comes from here in turtle.py:
def _incrementudc(self):
"""Increment update counter."""
if not TurtleScreen._RUNNING:
TurtleScreen._RUNNING = True
raise Terminator
if self._tracing > 0:
self._updatecounter += 1
self._updatecounter %= self._tracing
I don't want to have to run this code twice every time so if anyone has a solution, I thank you in advance.
Don't call both:
sc.exitonclick()
mainloop()
It's one or the other as exitonclick() simply sets up the exit key event and calls mainloop()
TurtleScreen._RUNNING is False when the program is executed for the first time, so it will enter the judgment formula and throw a Terminator exception
TurtleScreen._RUNNING is True when the program is executed for the second time, skipping the judgment formula, so it executes smoothly.
Delete raise Terminator, you can solve the problem.
I can see from your filepath that you are running it from spyder. The turtle module uses a class variable TurtleScreen._RUNNING which remains false after a destroy between executions when running in spyder instead of running it as a self contained script. I have requested for the module to be updated.
Meanwhile, work around/working examples
1)
import os
import importlib
import turtle
importlib.reload(turtle)
sc = Screen()
sc.setup(600,600)
image = os.path.expanduser(r"~\OneDrive\Desktop\AlienGameImage.gif")
sc.register_shape(image)
t = turtle.Turtle()
t.shape(image)
sc.exitonclick()
import os
import turtle
sc = Screen()
sc.setup(600,600)
image = os.path.expanduser(r"~\OneDrive\Desktop\AlienGameImage.gif")
sc.register_shape(image)
turtle.TurtleScreen._RUNNING=True
t = turtle.Turtle()
t.shape(image)
sc.exitonclick()

I am having an error 'pyimage1' doesn't exist while opening image in turtle with tkinter button

Althogh it works perfectly fine with built in turtle shapes it doesn't work with
new registered shapes.The error is pyimage1 doesn't exist and both my program and file are in the same directories
Here is the code
root=Tk()
import turtle
def image():
global img
img='batman.gif'
player=turtle.Turtle()
wn=turtle.Screen()
wn.register_shape(img)
player.shape(img)
B=Button(root,text='click',command=image).pack()```
The error shown is:```Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Users\dell\AppData\Local\Programs\Python\Python37\lib\tkinter\__init__.py", line 1705, in __call__
return self.func(*args)
File "C:\Users\dell\OneDrive\Desktop\imagetk.py", line 10, in image
player.shape(img)
File "C:\Users\dell\AppData\Local\Programs\Python\Python37\lib\turtle.py", line 2777, in shape
self.turtle._setshape(name)
File "C:\Users\dell\AppData\Local\Programs\Python\Python37\lib\turtle.py", line 2506, in _setshape
self._item = screen._createimage(screen._shapes["blank"]._data)
File "C:\Users\dell\AppData\Local\Programs\Python\Python37\lib\turtle.py", line 723, in _createimage
return self.cv.create_image(0, 0, image=image)
File "<string>", line 1, in create_image
File "C:\Users\dell\AppData\Local\Programs\Python\Python37\lib\tkinter\__init__.py", line 2489, in create_image
return self._create('image', args, kw)
File "C:\Users\dell\AppData\Local\Programs\Python\Python37\lib\tkinter\__init__.py", line 2480, in _create
*(args + self._options(cnf, kw))))
_tkinter.TclError: image "pyimage1" doesn't exist```
The problem is the way you're mixing turtle and tkinter is creating two roots which leads to this error. You're trying to use standalone turtle when you should be using embedded turtle. I.e. you should be using RawTurtle instead of Turtle and RawScreen instead of Screen. But don't just swap the names, look them up in the documentation. Your code should look roughly like:
from tkinter import *
from turtle import TurtleScreen, RawTurtle
IMAGE = 'batman.gif'
def image():
player = RawTurtle(screen)
player.shape(IMAGE)
root = Tk()
Button(root, text='click', command=image).pack()
canvas = Canvas(root)
canvas.pack()
screen = TurtleScreen(canvas)
screen.register_shape(IMAGE)
screen.mainloop()

tkinter picture error: bad screen distance

I'm trying to write a tkinter program, and I came across an error that I've never seen before while working with tkinter. I've searched around everywhere, and tried everything I can think of. This is my code so far:
x=tk.Canvas(top,width=1000,height=750,bg="grey")
x.pack()
y=tk.PhotoImage(file="C:\\Users\\Admin\\Desktop\\images (3)_CnyokaDvJmG1xu.png")
x.create_image(top,0,0,image=y)`
and this is error
Traceback (most recent call last):
File "C:\Users\Admin\Anaconda3\lib\tkinter\__init__.py", line
1705, in __call__
return self.func(*args)
File "C:/Users/Admin/.spyder-py3/temp.py", line 16, in open
x.create_image(top,0,0,image=y).pack()
File "C:\Users\Admin\Anaconda3\lib\tkinter\__init__.py", line
2489, in create_image
return self._create('image', args, kw)
File "C:\Users\Admin\Anaconda3\lib\tkinter\__init__.py", line
2480, in _create
*(args + self._options(cnf, kw))))
_tkinter.TclError: bad screen distance "."
You don't have to supply containing widget when placing an image in a canvas, coordinates are enough:
x.create_image(0,0,image=y)
The error is because canvas does not accept a widget as coordinates.

RuntimeError: main thread is not in main loop while using tkinter.simpledialog

Here is my code:
import threading
import tkinter.simpledialog
def showDialog(evt):
dlg = tkinter.simpledialog.SimpleDialog(root,text='Test!', buttons=['OK'])
dlg.go()
def test():
threading.Thread(target=root.event_generate, args=('<<showDialog>>',)).start()
root = tkinter.Tk()
root.bind('<<showDialog>>',showDialog)
tkinter.Button(text = 'showDialog',command = test).pack()
root.mainloop()
I run this code with Python3.4
The First time I click showDialog Button it work perfectly
but if I press OK and click the button again,it raise a RuntimeError:
Exception in thread Thread-2:
Traceback (most recent call last):
File "D:\Program Files\Python34\lib\threading.py", line 921, in _bootstrap_inner
self.run()
File "D:\Program Files\Python34\lib\threading.py", line 869, in run
self._target(*self._args, **self._kwargs)
File "D:\Program Files\Python34\lib\tkinter\__init__.py", line 1501, in event_generate
self.tk.call(args)
RuntimeError: main thread is not in main loop
I'm learning python recently,this code is just a demo.I want to do some work after press the button in sub-thread,because it will cost a few second and I don't want to stuck the UI. When the work is done,it will show a dialog.?
Can someone please tell me how can I do this using tkinter and why this problem occur?
Thanks!And sorry for my poor English.
Mixing threads with GUIs, and in particular tk, is tricky. I do not know all the rules, but unpredictable exceptions and deadlocks are two of the problems. I am a bit surprised that generating an event in a separate thread from the main thread and mainloop worked even once. (Why are you trying that?) A simplified function that run in the same thread does work consistently.
def test():
root.event_generate('<<showDialog>>')

Categories

Resources