How to create just one straight line with mouse on tkinter? - python

I want to create just one straight line and also add some button to reset it, and from there, create another one.
Currently my code creates one straight lime with the mouse, but if after I finished the first line I click it creates another line.
import tkinter as tk
from PIL import ImageTk
root = tk.Tk()
canvas = tk.Canvas(width = 600, height = 400)
canvas.pack(expand = tk.YES, fill = tk.BOTH)
coords = {"x":0,"y":0,"x2":0,"y2":0}
# keep a reference to all lines by keeping them in a list
lines = []
def click(e):
# define start point for line
coords["x"] = e.x
coords["y"] = e.y
# create a line on this point and store it in the list
l = lines.append(canvas.create_line(coords["x"],coords["y"],coords["x"],coords["y"], width=5, fill='red'))
def drag(e):
# update the coordinates from the event
coords["x2"] = e.x
coords["y2"] = e.y
print(e.x, e.y)
# Change the coordinates of the last created line to the new coordinates
l = canvas.coords(lines[-1], coords["x"],coords["y"],coords["x2"],coords["y2"])
canvas.itemconfigure(l, fill="black")
canvas.bind("<ButtonPress-1>", click)
canvas.bind("<B1-Motion>", drag)
print(coords["x"],coords["y"],coords["x2"],coords["y2"])
root.mainloop()

My original comment was:
Your click function always defines a new start point for a new line. Are you saying you want to draw a line continuing from the end of the previous line? Then you have to suppress the creation of a new start point if you have a line in progress. Perhaps using a line_in_progress flag or starting out with None values in coords to indicate the next click is a start of a new line.
If that's what you wanted, here's easy changes:
Just change your coords initialization to:
coords = {"x":None,"y":0,"x2":0,"y2":0} # none flag indicates start of line
and change your click code to:
def click(e):
if coords["x"] is None:
# define start point for line
coords["x"] = e.x
coords["y"] = e.y
# create a line on this point and store it in the list
l = lines.append(canvas.create_line(coords["x"],coords["y"],coords["x"],coords["y"], width=5, fill='red'))
else:
coords["x"] = coords["x2"]
coords["y"] = coords["y2"]
coords["x2"] = e.x
coords["y2"] = e.y
l = lines.append(canvas.create_line(coords["x"],coords["y"],coords["x2"],coords["y2"], width=5, fill='red'))
And when you want the next click to actually start a brand new line, just set coords["x"]=None before clicking (perhaps with another button, or maybe a right-click)

Related

How to cancel a running function through a variable=false condition in tkinter canvas action

Im trying to stop well-working drawing function through a stop button. After pressing the start button I can insert rectangles. That's what I want. However, if I activate the stop button (see code below) which set the condition to insert = false, stil can insert rectangles. This should not be the case. What's going wrong?
import tkinter as tk
def insert_cells():
global insert
def xyposition(event):
x = canvas.canvasx(event.x)
y = canvas.canvasy(event.y)
c = cell-1
x0 = int((x//cell)*cell+1)
y0 = int((y//cell)*cell+1)
canvas.create_rectangle(x0,y0,x0+c,y0+c, width=0, fill='green')
if not(insert):
return
else:
canvas.bind("<Button-1>", xyposition)
def stop_insert_cells():
global insert
insert = False
# MAIN
root = tk.Tk()
root.geometry("400x400")
n=30
m=30
cell=10
w = n*cell
h = m*cell
# canvas
canvas = tk.Canvas(root,width = w, height = h, borderwidth = 0, highlightthickness=0)
canvas.place(x=20, y=20)
# border canvas
canvas.create_rectangle(0,0,w-1,h-1, outline = 'black')
# raster canvas
x1 = 1
y1 = 1
x2 = w-2
y2 = h-2
for i in range(1,m): # horizontal lines
canvas.create_line(x1,i*cell,x2,i*cell)
for i in range(1,n): # vertical lines
canvas.create_line(i*cell,y1,i*cell,y2)
# cell filling
insert = True
start_insert_button = tk.Button(root, text='start', command = insert_cells)
stop_insert_button = tk.Button(root, text = 'stop', command = stop_insert_cells)
stop_insert_button.pack(side='bottom')
start_insert_button.pack(side='bottom')
root.mainloop()
Since you have binded the <Button-1> event to a callback when the start button is clicked, but do not unbind the callback when the stop button is clicked. So the binded callback will still be called when the canvas is clicked.
Either you unbind the callback (in this case, do not need the global variable insert):
def insert_cells():
def xyposition(event):
x = canvas.canvasx(event.x)
y = canvas.canvasy(event.y)
c = cell-1
x0 = int((x//cell)*cell+1)
y0 = int((y//cell)*cell+1)
canvas.create_rectangle(x0,y0,x0+c,y0+c, width=0, fill='green')
canvas.bind("<Button-1>", xyposition)
def stop_insert_cells():
canvas.unbind('<Button-1>')
or bind the callback at program start, then setting global variable insert to start or stop the insertion:
def xyposition(event):
if insert:
x = canvas.canvasx(event.x)
y = canvas.canvasy(event.y)
c = cell-1
x0 = int((x//cell)*cell+1)
y0 = int((y//cell)*cell+1)
canvas.create_rectangle(x0,y0,x0+c,y0+c, width=0, fill='green')
def insert_cells():
global insert
insert = True
def stop_insert_cells():
global insert
insert = False
...
# cell filling
insert = False
canvas.bind('<Button-1>', xypostion)
Note that your code may create multiple rectangles at the same cell. Better do some housekeeping to check whether the rectangle at the cell is already created.

'Move object' function bound to a key in Tkinter can only make one object move at a time, how to make more object move at the same time?

I've bound a key to a function which makes an oval (included in a list of other identical ovals) moves a certain distance. I want it to make a new oval moves each time I press the key, without stopping the previous moving oval if its course is not over.
With my code, by pressing 'c', I create a new oval randomly placed on the canvas, and saved in a dictionary. Each new oval is saved with key = 'compteur', 'compteur' increments for every new oval created to make sure every oval is not created over a previous existing one.
By pressing 'm', I want to make a new oval move each time I press the key, without the previous one stopping.
from tkinter import *
import time
from random import *
import time
compteur = 0
dic = {}
w = Tk()
w.geometry('400x400')
c = Canvas(w, width = 400, height = 400)
c.pack()
dic[compteur] = c.create_oval(200,150,250,200,fill = 'pink')
compteur += 1
def create(event):
global compteur
b = randrange(300)
dic[compteur] = c.create_oval(200,b,250,(b+50),fill = 'pink')
compteur += 1
def move(event):
rond = dic[randrange(len(dico))]
if c.coords(rond)[0] == 200:
for x in range (15):
c.move(rond,-10,0)
w.update()
time.sleep(0.15)
w.bind('<m>', move)
w.bind('<c>',create)
w.mainloop()
I'm obviously missing something but as I'm a beginner, I have no idea why only one oval can move at a time. And weirdly, once the second oval finish it's course, the first one starts again to finish its course too.
Thanks for your help :)
I use list to keep all circles.
In move() I move last circle from list only when I press <m>
In move_other() I move all circles except last one and use after() to run move_other() after 100ms (0.1s) so it will move all time.
from tkinter import *
from random import *
# --- fucntions ---
def create(event):
b = randrange(300)
circles.append(c.create_oval(200, b, 250, (b+50), fill='pink'))
def move(event):
item = circles[-1]
c.move(item, -10, 0)
def move_other():
for item in circles[:-1]:
c.move(item, -10, 0)
w.after(100, move_other)
# --- main ---
circles = []
w = Tk()
w.geometry('400x400')
c = Canvas(w, width=400, height=400)
c.pack()
circles.append(c.create_oval(200, 150, 250, 200, fill='pink'))
move_other() # start moving other circles
w.bind('<m>', move)
w.bind('<c>', create)
w.mainloop()

Stop Tkinter from opening a second window when importing drawing function

I am having an issue that I am having trouble resolving. I am making a Python interface with Tkinter that allows the user to draw a predefined figure with some parameters (number and length). The predefined figure function "tree" is in a second python file. The app runs fine if the "tree" function is in the main python file i.e everything draws in one window. If I put the figure "tree" in a second python file (figures.py) and try to import it the app will create a second window and the tree figure will draw there instead of the intended main window. How can I reference and import the function so that it draws in the main app window. Thanks!
main python file
import turtle
import tkinter
from tkinter.ttk import *
import figures
# Main function is defined.
def main():
# Set root and create canvas
root = tkinter.Tk()
root.title("Draw")
canvas = tkinter.Canvas(root, width=800, height=700)
canvas.pack(side=tkinter.RIGHT)
# create a turtle to draw on the canvas
pen = turtle.RawTurtle(canvas)
screen = pen.getscreen()
# Set screen co-ordinates.
screen.setworldcoordinates(-200, -700, 800, 700)
screen.bgcolor("grey")
# Draw frame
frame = tkinter.Frame(root, bg="white")
frame.pack(side=tkinter.LEFT, fill=tkinter.BOTH)
pointLabel = tkinter.Label(frame, text="Fractal", bg="white", )
pointLabel.pack()
# make the dropdown for fractal list
turtleNames = ["Tree", "Dandelion"]
turtleStr = tkinter.StringVar()
turtleList = OptionMenu(frame, turtleStr, turtleNames[0], *turtleNames)
turtleList.pack()
numberLabel = tkinter.Label(frame, text="Number")
numberLabel.pack()
# the entry widget must be given a string.
number = tkinter.StringVar()
numberEntry = tkinter.Entry(frame, textvariable=number)
numberEntry.pack()
number.set(str(3))
lengthLabel = tkinter.Label(frame, text="Length")
lengthLabel.pack()
# User sets length
length = tkinter.StringVar()
lengthEntry = tkinter.Entry(frame, textvariable=length)
lengthEntry.pack()
length.set(str(200))
def drawHandler():
# get the value from orderStr and make int
num = int(number.get())
# get the value from lengthStr and make int
len = int(length.get())
figures.tree(num, len)
# Event handler to clear canvas for a new drawing
def clearHandler():
pen.clear()
# This is an event handler. Handling the quit button press results in quitting the application.
def quitHandler():
root.destroy()
root.quit()
# Draw Buttons
# presses of the "Draw" button.
drawButton = tkinter.Button(frame, text="Draw", command=drawHandler)
drawButton.pack()
# presses of the "Clear" button.
clearButton = tkinter.Button(frame, text="Clear", command=clearHandler)
clearButton.pack()
# presses of the "Quit" button.
quitButton = tkinter.Button(frame, text="Quit", command=quitHandler)
quitButton.pack()
# tells the application to enter its event processing loop
tkinter.mainloop()
# Python jumps right here after executing the def main() line. These two lines tell
if __name__ == "__main__":
main()
figures.py for storing predefined designs
from turtle import *
pen = Pen()
screen = Screen()
# 1st figure Tree
def tree(n, l):
if n == 0 or l < 2:
return
# endif
pen.forward(l)
pen.left(45)
tree(n - 1, l / 2)
pen.right(90)
tree(n - 1, l / 2)
pen.left(45)
pen.backward(l)
The app runs fine if the "tree" function is in the main python file
i.e everything draws in one window. If I put the figure "tree" in a
second python file (figures.py) and try to import it the app will
create a second window and the tree figure will draw there instead of
the intended main window.
The problem is that figures.py is setting up a turtle environment independent of the main program -- don't let it. Pass in to the figures.py functions whatever they need to operate in the main program's turtle environment:
figures.py
# 1st figure Tree
def tree(pen, number, length):
if number == 0 or length < 2:
return
pen.forward(length)
pen.left(45)
tree(pen, number - 1, length / 2)
pen.right(90)
tree(pen, number - 1, length / 2)
pen.left(45)
pen.backward(length)
# test this code standalone
if __name__ == "__main__":
import turtle
tree(turtle.getpen(), 5, 100) # test using default turtle
turtle.exitonclick()
The code at the bottom of the file is so you can test this file independently. When imported into the main program, it will be ignored. Now we just need a small change to the main program:
main python file
def drawHandler():
# get the value from orderStr and make int
number_int = int(number.get())
# get the value from lengthStr and make int
length_int = int(length.get())
figures.tree(pen, number_int, length_int)
I changed the variable names as you were redefining Python's built-in len function.

I'm trying to make a simple line drawing program with tkinter but it won't work

I'm trying to make this really simple program, all it does is store the current x/y pos of the mouse on the canvas and then use them to draw a line when you click for the second time. I've already bound it and I'm not getting any errors, it seems like it's not even being activated. Any help is greatly appreciated
from tkinter import *
main = Tk()
c = Canvas(main, width=600, height=600)
c.pack()
#For colored lines
presses = 0
def click(event):
if presses == 0:
initX = int(c.canvasx(event.x))
initY = int(c.canvasy(event.y))
presses == 1
elif presses == 1:
c.create_line(initX, initY,
int(c.canvasx(event.x)),
int(c.canvasy(event.y)))
presses == 0
c.bind("<Button-1>", click)
mainloop()
How does something like this work for you?
from tkinter import *
main = Tk()
c = Canvas(main, width=600, height=600)
c.pack()
line = []
def click(event):
global line
X = int(c.canvasx(event.x))
Y = int(c.canvasy(event.y))
line.append((X,Y))
if len(line) > 1:
startX,startY = line[-2]
c.create_line(startX, startY, X, Y)
c.bind("<Button-1>", click)
mainloop()
I've changed around your code a bit to store a list of the X,Y coordinates that have been clicked on. If more than 1 point on the screen has been clicked, it will draw a line between the current point clicked on and the last point clicked on.
Reason your code wasn't working was that initX and initY are forgotten in between calls on the the click function. Adding them to a list solves this.

(PY)Object has no attribute error

# The imports include turtle graphics and tkinter modules.
# The colorchooser and filedialog modules let the user
# pick a color and a filename.
import turtle
import tkinter
import tkinter.colorchooser
import tkinter.filedialog
import xml.dom.minidom
# The following classes define the different commands that
# are supported by the drawing application.
class GoToCommand:
def __init__(self,x,y,width=1,color="black"):
self.x = x
self.y = y
self.width = width
self.color = color
# The draw method for each command draws the command
# using the given turtle
def draw(self,turtle):
turtle.width(self.width)
turtle.pencolor(self.color)
turtle.goto(self.x,self.y)
# The __str__ method is a special method that is called
# when a command is converted to a string. The string
# version of the command is how it appears in the graphics
# file format.
def __str__(self):
return '<Command x="' + str(self.x) + '" y="' + str(self.y) + \
'" width="' + str(self.width) \
+ '" color="' + self.color + '">GoTo</Command>'
class CircleCommand:
def __init__(self,radius, width=1,color="black"):
self.radius = radius
self.width = width
self.color = color
def draw(self,turtle):
turtle.width(self.width)
turtle.pencolor(self.color)
turtle.circle(self.radius)
def __str__(self):
return '<Command radius="' + str(self.radius) + '" width="' + \
str(self.width) + '" color="' + self.color + '">Circle</Command>'
class TextCommand:
def __init__(self, move=False, align="left", font=("Arial", 8, "normal")):
self.move = move
self.align = align
self.font = font
def draw(self,turtle):
#turtle.write("test",self.move,self.align,self.font)
turtle.move(self.move)
turtle.align(self.align)
turtle.font(self.font)
def __str__(self):
return '<Command TODO ENTER COMMAND>'
class BeginFillCommand:
def __init__(self,color):
self.color = color
def draw(self,turtle):
turtle.fillcolor(self.color)
turtle.begin_fill()
def __str__(self):
return '<Command color="' + self.color + '">BeginFill</Command>'
class EndFillCommand:
def __init__(self):
pass
def draw(self,turtle):
turtle.end_fill()
def __str__(self):
return "<Command>EndFill</Command>"
class PenUpCommand:
def __init__(self):
pass
def draw(self,turtle):
turtle.penup()
def __str__(self):
return "<Command>PenUp</Command>"
class PenDownCommand:
def __init__(self):
pass
def draw(self,turtle):
turtle.pendown()
def __str__(self):
return "<Command>PenDown</Command>"
# This is the PyList container object. It is meant to hold a
class PyList:
def __init__(self):
self.gcList = []
# The append method is used to add commands to the sequence.
def append(self,item):
self.gcList = self.gcList + [item]
# This method is used by the undo function. It slices the sequence
# to remove the last item
def removeLast(self):
self.gcList = self.gcList[:-1]
# This special method is called when iterating over the sequence.
# Each time yield is called another element of the sequence is returned
# to the iterator (i.e. the for loop that called this.)
def __iter__(self):
for c in self.gcList:
yield c
# This is called when the len function is called on the sequence.
def __len__(self):
return len(self.gcList)
# This class defines the drawing application. The following line says that
# the DrawingApplication class inherits from the Frame class. This means
# that a DrawingApplication is like a Frame object except for the code
# written here which redefines/extends the behavior of a Frame.
class DrawingApplication(tkinter.Frame):
def __init__(self, master=None):
super().__init__(master)
self.pack()
self.buildWindow()
self.graphicsCommands = PyList()
# This method is called to create all the widgets, place them in the GUI,
# and define the event handlers for the application.
def buildWindow(self):
# The master is the root window. The title is set as below.
self.master.title("Draw")
# Here is how to create a menu bar. The tearoff=0 means that menus
# can't be separated from the window which is a feature of tkinter.
bar = tkinter.Menu(self.master)
fileMenu = tkinter.Menu(bar,tearoff=0)
# This code is called by the "New" menu item below when it is selected.
# The same applies for loadFile, addToFile, and saveFile below. The
# "Exit" menu item below calls quit on the "master" or root window.
def newWindow():
# This sets up the turtle to be ready for a new picture to be
# drawn. It also sets the sequence back to empty. It is necessary
# for the graphicsCommands sequence to be in the object (i.e.
# self.graphicsCommands) because otherwise the statement:
# graphicsCommands = PyList()
# would make this variable a local variable in the newWindow
# method. If it were local, it would not be set anymore once the
# newWindow method returned.
theTurtle.clear()
theTurtle.penup()
theTurtle.goto(0,0)
theTurtle.pendown()
screen.update()
screen.listen()
self.graphicsCommands = PyList()
fileMenu.add_command(label="New",command=newWindow)
# The parse function adds the contents of an XML file to the sequence.
def parse(filename):
xmldoc = xml.dom.minidom.parse(filename)
graphicsCommandsElement = xmldoc.getElementsByTagName("GraphicsCommands")[0]
graphicsCommands = graphicsCommandsElement.getElementsByTagName("Command")
for commandElement in graphicsCommands:
print(type(commandElement))
command = commandElement.firstChild.data.strip()
attr = commandElement.attributes
if command == "GoTo":
x = float(attr["x"].value)
y = float(attr["y"].value)
width = float(attr["width"].value)
color = attr["color"].value.strip()
cmd = GoToCommand(x,y,width,color)
elif command == "Circle":
radius = float(attr["radius"].value)
width = float(attr["width"].value)
color = attr["color"].value.strip()
cmd = CircleCommand(radius,width,color)
elif command == "BeginFill":
color = attr["color"].value.strip()
cmd = BeginFillCommand(color)
elif command == "EndFill":
cmd = EndFillCommand()
elif command == "PenUp":
cmd = PenUpCommand()
elif command == "PenDown":
cmd = PenDownCommand()
else:
raise RuntimeError("Unknown Command: " + command)
self.graphicsCommands.append(cmd)
def loadFile():
filename = tkinter.filedialog.askopenfilename(title="Select a Graphics File")
newWindow()
# This re-initializes the sequence for the new picture.
self.graphicsCommands = PyList()
# calling parse will read the graphics commands from the file.
parse(filename)
for cmd in self.graphicsCommands:
cmd.draw(theTurtle)
# This line is necessary to update the window after the picture is drawn.
screen.update()
fileMenu.add_command(label="Load...",command=loadFile)
def addToFile():
filename = tkinter.filedialog.askopenfilename(title="Select a Graphics File")
theTurtle.penup()
theTurtle.goto(0,0)
theTurtle.pendown()
theTurtle.pencolor("#000000")
theTurtle.fillcolor("#000000")
cmd = PenUpCommand()
self.graphicsCommands.append(cmd)
cmd = GoToCommand(0,0,1,"#000000")
self.graphicsCommands.append(cmd)
cmd = PenDownCommand()
self.graphicsCommands.append(cmd)
screen.update()
parse(filename)
for cmd in self.graphicsCommands:
cmd.draw(theTurtle)
screen.update()
fileMenu.add_command(label="Load Into...",command=addToFile)
# The write function writes an XML file to the given filename
def write(filename):
file = open(filename, "w")
file.write('<?xml version="1.0" encoding="UTF-8" standalone="no" ?>\n')
file.write('<GraphicsCommands>\n')
for cmd in self.graphicsCommands:
file.write(' '+str(cmd)+"\n")
file.write('</GraphicsCommands>\n')
file.close()
def saveFile():
filename = tkinter.filedialog.asksaveasfilename(title="Save Picture As...")
write(filename)
fileMenu.add_command(label="Save As...",command=saveFile)
fileMenu.add_command(label="Exit",command=self.master.quit)
bar.add_cascade(label="File",menu=fileMenu)
# This tells the root window to display the newly created menu bar.
self.master.config(menu=bar)
# Here several widgets are created. The canvas is the drawing area on
# the left side of the window.
canvas = tkinter.Canvas(self,width=600,height=600)
canvas.pack(side=tkinter.LEFT)
# By creating a RawTurtle, we can have the turtle draw on this canvas.
# Otherwise, a RawTurtle and a Turtle are exactly the same.
theTurtle = turtle.RawTurtle(canvas)
# This makes the shape of the turtle a circle.
theTurtle.shape("circle")
screen = theTurtle.getscreen()
# This causes the application to not update the screen unless
# screen.update() is called. This is necessary for the ondrag event
# handler below. Without it, the program bombs after dragging the
# turtle around for a while.
screen.tracer(0)
# This is the area on the right side of the window where all the
# buttons, labels, and entry boxes are located. The pad creates some empty
# space around the side. The side puts the sideBar on the right side of the
# this frame. The fill tells it to fill in all space available on the right
# side.
sideBar = tkinter.Frame(self,padx=5,pady=5)
sideBar.pack(side=tkinter.RIGHT, fill=tkinter.BOTH)
# This is a label widget. Packing it puts it at the top of the sidebar.
pointLabel = tkinter.Label(sideBar,text="Width")
pointLabel.pack()
# This entry widget allows the user to pick a width for their lines.
# With the widthSize variable below you can write widthSize.get() to get
# the contents of the entry widget and widthSize.set(val) to set the value
# of the entry widget to val. Initially the widthSize is set to 1. str(1) is
# needed because the entry widget must be given a string.
widthSize = tkinter.StringVar()
widthEntry = tkinter.Entry(sideBar,textvariable=widthSize)
widthEntry.pack()
widthSize.set(str(1))
radiusLabel = tkinter.Label(sideBar,text="Radius")
radiusLabel.pack()
radiusSize = tkinter.StringVar()
radiusEntry = tkinter.Entry(sideBar,textvariable=radiusSize)
radiusSize.set(str(10))
radiusEntry.pack()
# A button widget calls an event handler when it is pressed. The circleHandler
# function below is the event handler when the Draw Circle button is pressed.
def circleHandler():
# When drawing, a command is created and then the command is drawn by calling
# the draw method. Adding the command to the graphicsCommands sequence means the
# application will remember the picture.
cmd = CircleCommand(float(radiusSize.get()), float(widthSize.get()), penColor.get())
cmd.draw(theTurtle)
self.graphicsCommands.append(cmd)
# These two lines are needed to update the screen and to put the focus back
# in the drawing canvas. This is necessary because when pressing "u" to undo,
# the screen must have focus to receive the key press.
screen.update()
screen.listen()
def textHandler():
# When drawing, a command is created and then the command is drawn by calling
# the draw method. Adding the command to the graphicsCommands sequence means the
# application will remember the picture.
cmd = TextCommand(False, penColor.get())
cmd.draw(theTurtle)
self.graphicsCommands.append(cmd)
# These two lines are needed to update the screen and to put the focus back
# in the drawing canvas. This is necessary because when pressing "u" to undo,
# the screen must have focus to receive the key press.
screen.update()
screen.listen()
# This creates the button widget in the sideBar. The fill=tkinter.BOTH causes the button
# to expand to fill the entire width of the sideBar.
circleButton = tkinter.Button(sideBar, text = "Draw Circle", command=circleHandler)
circleButton.pack(fill=tkinter.BOTH)
textButton = tkinter.Button(sideBar, text = "Draw Text", command=textHandler)
textButton.pack(fill=tkinter.BOTH)
# The color mode 255 below allows colors to be specified in RGB form (i.e. Red/
# Green/Blue). The mode allows the Red value to be set by a two digit hexadecimal
# number ranging from 00-FF. The same applies for Blue and Green values. The
# color choosers below return a string representing the selected color and a slice
# is taken to extract the #RRGGBB hexadecimal string that the color choosers return.
screen.colormode(255)
penLabel = tkinter.Label(sideBar,text="Pen Color")
penLabel.pack()
penColor = tkinter.StringVar()
penEntry = tkinter.Entry(sideBar,textvariable=penColor)
penEntry.pack()
# This is the color black.
penColor.set("#000000")
def getPenColor():
color = tkinter.colorchooser.askcolor()
if color != None:
penColor.set(str(color)[-9:-2])
penColorButton = tkinter.Button(sideBar, text = "Pick Pen Color", command=getPenColor)
penColorButton.pack(fill=tkinter.BOTH)
fillLabel = tkinter.Label(sideBar,text="Fill Color")
fillLabel.pack()
fillColor = tkinter.StringVar()
fillEntry = tkinter.Entry(sideBar,textvariable=fillColor)
fillEntry.pack()
fillColor.set("#000000")
def getFillColor():
color = tkinter.colorchooser.askcolor()
if color != None:
fillColor.set(str(color)[-9:-2])
fillColorButton = \
tkinter.Button(sideBar, text = "Pick Fill Color", command=getFillColor)
fillColorButton.pack(fill=tkinter.BOTH)
def beginFillHandler():
cmd = BeginFillCommand(fillColor.get())
cmd.draw(theTurtle)
self.graphicsCommands.append(cmd)
beginFillButton = tkinter.Button(sideBar, text = "Begin Fill", command=beginFillHandler)
beginFillButton.pack(fill=tkinter.BOTH)
def endFillHandler():
cmd = EndFillCommand()
cmd.draw(theTurtle)
self.graphicsCommands.append(cmd)
endFillButton = tkinter.Button(sideBar, text = "End Fill", command=endFillHandler)
endFillButton.pack(fill=tkinter.BOTH)
penLabel = tkinter.Label(sideBar,text="Pen Is Down")
penLabel.pack()
def penUpHandler():
cmd = PenUpCommand()
cmd.draw(theTurtle)
penLabel.configure(text="Pen Is Up")
self.graphicsCommands.append(cmd)
penUpButton = tkinter.Button(sideBar, text = "Pen Up", command=penUpHandler)
penUpButton.pack(fill=tkinter.BOTH)
def penDownHandler():
cmd = PenDownCommand()
cmd.draw(theTurtle)
penLabel.configure(text="Pen Is Down")
self.graphicsCommands.append(cmd)
penDownButton = tkinter.Button(sideBar, text = "Pen Down", command=penDownHandler)
penDownButton.pack(fill=tkinter.BOTH)
# Here is another event handler. This one handles mouse clicks on the screen.
def clickHandler(x,y):
# When a mouse click occurs, get the widthSize entry value and set the width of the
# pen to the widthSize value. The float(widthSize.get()) is needed because
# the width is an integer, but the entry widget stores it as a string.
cmd = GoToCommand(x,y,float(widthSize.get()),penColor.get())
cmd.draw(theTurtle)
self.graphicsCommands.append(cmd)
screen.update()
screen.listen()
# Here is how we tie the clickHandler to mouse clicks.
screen.onclick(clickHandler)
def dragHandler(x,y):
cmd = GoToCommand(x,y,float(widthSize.get()),penColor.get())
cmd.draw(theTurtle)
self.graphicsCommands.append(cmd)
screen.update()
screen.listen()
theTurtle.ondrag(dragHandler)
# the undoHandler undoes the last command by removing it from the
# sequence and then redrawing the entire picture.
def undoHandler():
if len(self.graphicsCommands) > 0:
self.graphicsCommands.removeLast()
theTurtle.clear()
theTurtle.penup()
theTurtle.goto(0,0)
theTurtle.pendown()
for cmd in self.graphicsCommands:
cmd.draw(theTurtle)
screen.update()
screen.listen()
screen.onkeypress(undoHandler, "u")
screen.listen()
# The main function in our GUI program is very simple. It creates the
# root window. Then it creates the DrawingApplication frame which creates
# all the widgets and has the logic for the event handlers. Calling mainloop
# on the frames makes it start listening for events. The mainloop function will
# return when the application is exited.
def main():
root = tkinter.Tk()
drawingApp = DrawingApplication(root)
drawingApp.mainloop()
print("Program Execution Completed.")
if __name__ == "__main__":
main()
Running the following code works flawlessly, once it is ran I would press the button labeled "Draw Text" and the following error is displayed:
C:\Python34\python.exe C:/Users/ThinkTank/PycharmProjects/untitled2/1/__init__.py
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Python34\lib\tkinter\__init__.py", line 1533, in __call__
return self.func(*args)
File "C:/Users/ThinkTank/PycharmProjects/untitled2/1/__init__.py", line 354, in textHandler
cmd.draw(theTurtle)
File "C:/Users/ThinkTank/PycharmProjects/untitled2/1/__init__.py", line 57, in draw
turtle.move(self.move)
AttributeError: 'RawTurtle' object has no attribute 'move'
There is a task which requires me to draw some text on a tkinter screen using turtle. I have added in code which tells the turtle to draw this if the button in the menu is pressed, but this error than shows up. I am rather new to python and don't understand how to go about fixing such a problem.
The problem is that the RawTurtle object, from the turtle module, has no attribute move. You can use the commands forward, backward, left, and right to move your turtle. Before using the above commands, I suggest looking at the documentation for the turtle module, as you seem to be confused about how to properly use it.
Here is a quick explanation for the basic turtle move methods:
turtle.forward(int\float): This method moves a turtle object forward(in pixels). Use a integer or a float to specify how far to move the turtle.
turtle.backward(int\float): This method moves a turtle object backwards(in pixels). Use a integer or a float to specify how far to move the turtle.
turtle.left(int\float): This method turns a turtle object left(in degrees). Use a integer or a float to specify how far to turn the turtle.
turtle.right(int\float): This method turns a turtle object right(in degrees). Use a integer or a float to specify how far to turn the turtle.
This is fairly straightforward. You initialize theTurtle in the caller to be a turtle.RawTurtle. RawTurtle doesn't have an attribute or method named move, it has special purpose methods for moving forward or backwards, and other methods to turn relatively (right and left) or to an absolute orientation (setheading).
If your goal is to, say, move the turtle forward by move "distance" or something from its current heading, you'd call forward/fd.

Categories

Resources