(Python 3) Odd error with Turtle controller ultilising Tkinter

206 Views Asked by At

So I've been working on a program called tdc (Turtle Design Creator), which basically uses Tkinter buttons to control a Turtle. The code:

global file
file = None
global rcd
rcd = False
global arrows
arrows = False
global arrowtoggle
def forwardless():
    t.forward(25)
    if rcd:
        file.write('t.forward(25)\n')
def backwardless():
    t.backward(25)
    if rcd:
        file.write('t.backward(25)\n')
def forward():
    t.forward(50)
    if rcd:
        file.write('t.forward(50)\n')
def left():
    t.left(90)
    if rcd:
        file.write('t.left(90)\n')
def right():
    t.right(90)
    if rcd:
        file.write('t.right(90)\n')
def diagleft():
    t.left(45)
    if rcd:
        file.write('t.left(45)\n')
def diagright():
    t.right(45)
    if rcd:
        file.write('t.right(45)\n')
def clear():
    t.reset()
    if rcd:
        file.write('t.reset()\n')
def backward():
    t.backward(50)
    if rcd:
        file.write('t.backward(50)\n')
def lift():
    t.up()
    if rcd:
        file.write('t.up()\n')
def drop():
    t.down()
    if rcd:
        file.write('t.down()\n')
def green():
    t.color(0, 0.5, 0)
    if rcd:
        file.write('t.color(0, 0.5, 0)\n')
def red():
    t.color(1, 0, 0)
    if rcd:
        file.write('t.color(1, 0, 0)\n')
def gold():
    t.color(0.9, 0.75, 0)
    if rcd:
        file.write('t.color(0.9, 0.75, 0)\n')
def blue():
    t.color(0, 0, 1)
    if rcd:
        file.write('t.color(0, 0, 1)\n')
def black():
    t.color(0, 0, 0)
    if rcd:
        file.write('t.up()\n')
def begin_fill():
    t.begin_fill()
    if rcd:
        file.write('t.begin_fill()\n')
def end_fill():
    t.end_fill()
    if rcd:
        file.write('t.end_fill()\n')
def small_circle():
    t.circle(10)
    if rcd:
        file.write('t.circle(10)\n')
def medium_circle():
    t.circle(30)
    if rcd:
        file.write('t.circle(30)\n')
def large_circle():
    t.circle(50)
    if rcd:
        file.write('t.circle(50)\n')
def steepdiagleft():
    t.left(25)
    if rcd:
        file.write('t.left(25)\n')
def steepdiagright():
    t.right(25)
    if rcd:
        file.write('t.right(25)\n')
def arrowkey():
    global arrows
    global arrowtoggle
    if not arrows:
        arrows = True
        arrowtoggle.config(text="Arrow Key Control: ON")
    else:
        arrows = False
        arrowtoggle.config(text="Arrow Key Control: OFF")
def right(event):
    global arrows
    global rcd
    if arrows:
        t.setheading(0)
        t.forward(5)
        if rcd:
            file.write('t.setheading(0)\nt.forward(5)\n')
def left(event):
    global arrows
    global rcd
    if arrows:
        t.setheading(180)
        t.forward(5)
        if rcd:
            file.write('t.setheading(180)\nt.forward(5)\n')
def up(event):
    global arrows
    global rcd
    if arrows:
        t.setheading(90)
        t.forward(5)
        if rcd:
            file.write('t.setheading(90)\nt.forward(5)\n')
def down(event):
    global arrows
    global rcd
    if arrows:
        t.setheading(270)
        t.forward(5)
        if rcd:
            file.write('t.setheading(270)\nt.forward(5)\n')
def startrcd():
    global rcd
    rcd = True
    global file
    while file == None:
        file = filedialog.asksaveasfile(mode="w", defaultextension=".py")
        if file == None:
            messagebox.showinfo('Recording Canceled', 'No file selected or created.')
            break
    if file != None:
        file.write('import turtle\nturtle.title(\'TDC Save\')\nturtle.setup(width=1000, height=500)\nt = turtle.Pen()\n')
        messagebox.showinfo('Started', 'Recording started.')
def endrcd():
    global rcd
    global file
    if rcd and file != None:
        rcd = False
        file.close()
        file = None
        messagebox.showinfo('Ended', 'Recording ended.')
def close():
    if messagebox.askyesno('Exit?', 'Are you sure you wish to exit?'):
        messagebox.showinfo('Closing', 'TDC is closing.')
        exit()
import turtle
import tkinter.messagebox
from tkinter import filedialog
turtle.setup(width=1000, height=500)
turtle.title('Turtle Design Creator')
t = turtle.Pen()
from tkinter import *
tk = Tk()
tk.title("Toolbox")
a = Button(tk, text="Forward 50", command=forward)
b = Button(tk, text="Left 90", command=left)
c = Button(tk, text="Right 90", command=right)
d = Button(tk, text="Left 45", command=diagleft)
e = Button(tk, text="Right 45", command=diagright)
f = Button(tk, text="Clear", command=clear)
g = Button(tk, text="Backward 50", command=backward)
h = Button(tk, text="Lift", command=lift)
i = Button(tk, text="Drop", command=drop)
j = Button(tk, text="Green", command=green)
k = Button(tk, text="Red", command=red)
l = Button(tk, text="Gold", command=gold)
m = Button(tk, text="Blue", command=blue)
n = Button(tk, text="Black", command=black)
o = Button(tk, text="Begin Fill", command=begin_fill)
p = Button(tk, text="End Fill", command=end_fill)
q = Button(tk, text="Small Circle", command=small_circle)
r = Button(tk, text="Medium Circle", command=medium_circle)
s = Button(tk, text="Large Circle", command=large_circle)
tt = Button(tk, text="Left 25", command=steepdiagleft)
u = Button(tk, text="Right 25", command=steepdiagright)
v = Button(tk, text="Start Recording", command=startrcd)
w = Button(tk, text="End Recording", command=endrcd)
x = Button(tk, text="Exit", command=close)
y = Button(tk, text="Forward 25", command=forwardless)
z = Button(tk, text="Backward 25", command=backwardless)
arrow = Button(tk, text="Arrow Key Control Toggle\n(only 90 degree angles)", command=arrowkey)
arrowtoggle = Label(tk, text="Arrow Key Control: OFF")
a.pack()
b.pack()
c.pack()
d.pack()
e.pack()
f.pack()
g.pack()
h.pack()
i.pack()
j.pack()
k.pack()
l.pack()
m.pack()
n.pack()
o.pack()
p.pack()
q.pack()
r.pack()
s.pack()
tt.pack()
u.pack()
v.pack()
w.pack()
x.pack()
y.pack()
z.pack()
arrow.pack()
arrowtoggle.pack()
tk.bind("<Right>", right)
tk.bind("<Left>", left)
tk.bind("<Up>", up)
tk.bind("<Down>", down)

(I know it's a lot of code!) But whenever I run it and click the Right 90 or Left 90 buttons, I get this error:

Exception in Tkinter callback
Traceback (most recent call last):
File "/usr/lib/python3.4/idlelib/run.py", line 121, in main
seq, request = rpc.request_queue.get(block=True, timeout=0.05)
File "/usr/lib/python3.4/queue.py", line 175, in get
raise Empty
queue.Empty

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "/usr/lib/python3.4/tkinter/__init__.py", line 1536, in __call__
return self.func(*args)
TypeError: left() missing 1 required positional argument: 'event'

What exactly is happening? All the other buttons work fine, and they have the same setup as left() (or right()).

Please help...

1

There are 1 best solutions below

0
On BEST ANSWER

It's likely because you have two functions called left():

def left():
    t.left(90)
    if rcd:
        file.write('t.left(90)\n')

def left(event):
    global arrows
    global rcd
    if arrows:
        t.setheading(180)
        t.forward(5)
        if rcd:
            file.write('t.setheading(180)\nt.forward(5)\n')

and two functions called right():

def right():
    t.right(90)
    if rcd:
        file.write('t.right(90)\n')

def right(event):
    global arrows
    global rcd
    if arrows:
        t.setheading(0)
        t.forward(5)
        if rcd:
            file.write('t.setheading(0)\nt.forward(5)\n')

Rename one pair and see if things improve

def hard_left():
    t.left(90)
    if rcd:
        file.write('t.left(90)\n')
def hard_right():
    t.right(90)
    if rcd:
        file.write('t.right(90)\n')

# ...

b = Button(tk, text="Left 90", command=hard_left)
c = Button(tk, text="Right 90", command=hard_right)

I know it's a lot of code!

I've reworked it below to make it slightly less code -- see if the changes make sense for your purposes. You're walking a tightrope when mixing Tk with turtle (which is built atop Tk) -- you've done an excellent job so far, just be aware the two can clash if/when you run into bugs.

import turtle
from tkinter import *
from tkinter import filedialog

file = None
rcd = False
arrows = False

def forward(distance=50):
    t.forward(distance)
    if rcd:
        file.write('t.forward({})\n'.format(distance))

def backward(distance=50):
    t.backward(distance)
    if rcd:
        file.write('t.backward({})\n'.format(distance))

def left(angle=90):
    t.left(angle)
    if rcd:
        file.write('t.left({})\n'.format(angle))

def right(angle=90):
    t.right(angle)
    if rcd:
        file.write('t.right({})\n'.format(angle))

def clear():
    t.reset()
    if rcd:
        file.write('t.reset()\n')

def lift():
    t.up()
    if rcd:
        file.write('t.up()\n')

def drop():
    t.down()
    if rcd:
        file.write('t.down()\n')

def color(r=0, g=0, b=0):
    t.color(r, g, b)
    if rcd:
        file.write('t.color({}, {}, {})\n'.format(r, g, b))

def begin_fill():
    t.begin_fill()
    if rcd:
        file.write('t.begin_fill()\n')

def end_fill():
    t.end_fill()
    if rcd:
        file.write('t.end_fill()\n')

def circle(radius=30):
    t.circle(radius)
    if rcd:
        file.write('t.circle({})\n'.format(radius))

def arrowkey():
    global arrows

    if not arrows:
        arrows = True
        arrowtoggle.config(text="Arrow Key Control: ON")
    else:
        arrows = False
        arrowtoggle.config(text="Arrow Key Control: OFF")

def handle_right(event):
    if arrows:
        t.setheading(0)
        t.forward(5)
        if rcd:
            file.write('t.setheading(0)\nt.forward(5)\n')

def handle_left(event):
    if arrows:
        t.setheading(180)
        t.forward(5)
        if rcd:
            file.write('t.setheading(180)\nt.forward(5)\n')

def handle_up(event):
    if arrows:
        t.setheading(90)
        t.forward(5)
        if rcd:
            file.write('t.setheading(90)\nt.forward(5)\n')

def handle_down(event):
    if arrows:
        t.setheading(270)
        t.forward(5)
        if rcd:
            file.write('t.setheading(270)\nt.forward(5)\n')

def startrcd():
    global rcd, file

    rcd = True

    while file is None:
        file = filedialog.asksaveasfile(mode="w", defaultextension=".py")
        if file is None:
            messagebox.showinfo('Recording Canceled', 'No file selected or created.')
            break
    if file != None:
        file.write("import turtle\nturtle.title('TDC Save')\n")
        file.write('turtle.setup(width=1000, height=500)\n')
        file.write('t = turtle.Turtle()\n')
        messagebox.showinfo('Started', 'Recording started.')

def endrcd():
    global rcd, file

    if rcd and file is not None:
        rcd = False
        file.close()
        file = None
        messagebox.showinfo('Ended', 'Recording ended.')

def close():
    if messagebox.askyesno('Exit?', 'Are you sure you wish to exit?'):
        messagebox.showinfo('Closing', 'TDC is closing.')
        exit()

turtle.setup(width=1000, height=500)
turtle.title('Turtle Design Creator')
t = turtle.Turtle()

tk = Tk()
tk.title("Toolbox")

items = []

items.append(Button(tk, text="Forward 50", command=forward))
items.append(Button(tk, text="Left 90", command=left))
items.append(Button(tk, text="Right 90", command=right))
items.append(Button(tk, text="Left 45", command=lambda: left(45)))
items.append(Button(tk, text="Right 45", command=lambda: right(45)))
items.append(Button(tk, text="Clear", command=clear))
items.append(Button(tk, text="Backward 50", command=backward))
items.append(Button(tk, text="Lift", command=lift))
items.append(Button(tk, text="Drop", command=drop))
items.append(Button(tk, text="Green", command=lambda: color(0, 0.5, 0)))
items.append(Button(tk, text="Red", command=lambda: color(1, 0, 0)))
items.append(Button(tk, text="Gold", command=lambda: color(0.9, 0.75, 0)))
items.append(Button(tk, text="Blue", command=lambda: color(0, 0, 1)))
items.append(Button(tk, text="Black", command=lambda: color(0, 0, 0)))
items.append(Button(tk, text="Begin Fill", command=begin_fill))
items.append(Button(tk, text="End Fill", command=end_fill))
items.append(Button(tk, text="Small Circle", command=lambda: circle(10)))
items.append(Button(tk, text="Medium Circle", command=circle))
items.append(Button(tk, text="Large Circle", command=lambda: circle(50)))
items.append(Button(tk, text="Left 25", command=lambda: left(25)))
items.append(Button(tk, text="Right 25", command=lambda: right(25)))
items.append(Button(tk, text="Start Recording", command=startrcd))
items.append(Button(tk, text="End Recording", command=endrcd))
items.append(Button(tk, text="Exit", command=close))
items.append(Button(tk, text="Forward 25", command=lambda: forward(25)))
items.append(Button(tk, text="Backward 25", command=lambda: backward(25)))
items.append(Button(tk, text="Arrow Key Control Toggle\n(only 90 degree angles)", command=arrowkey))

arrowtoggle = Label(tk, text="Arrow Key Control: OFF")
items.append(arrowtoggle)

for item in items:
    item.pack()

tk.bind("<Right>", handle_right)
tk.bind("<Left>", handle_left)
tk.bind("<Up>", handle_up)
tk.bind("<Down>", handle_down)

turtle.mainloop()