Python - Tkinter event_generate not detected by bind - python

I have two classes (one called 'Point' one called 'PointConector'), both of which inherits 'Frame' (Im not sure If I need to but was seeing if it helped)
When I move the Point (mouse Enter/Leave) and drag the point around, I want to fire off an event for 'PointConnector' (which is a line thats joins the twp points) to pick up the event and redraw the line with the new position of the point.
If I use the event_generate from the canvas object and bind also from the canvas object then the event is picked up, but the object that is passed is the canvas object, not the Point object.
If I fire the event_generate from the Point object (which is inherited from Frame) then the event is ignored
I need the bind event to have the Widget field set to the 'Point' that generated the event. ie I need to have a handle to the point that fired the event. So the Field 'Widget' in the event should be the Point object that is being handled, not the canvas.
from tkinter import Tk, Canvas,Frame
class pointConnector(Frame):
point1 = None
point2 = None
connector = None
def __init__(self,canvas, point1,point2):
super(pointConnector,self).__init__(canvas)
self.point1 = point1
self.point2 = point2
self.canvas = canvas
p1 = self.canvas.translatePoint((self.point1.x,self.point1.y))
p2 = self.canvas.translatePoint((self.point2.x,self.point2.y))
self.connector = canvas.create_line(p1[0], p1[1], p2[0], p2[1],fill='red',state="hidden", width =2)
self.canvas.bind("<<foo>>",self.dummy)
def dummy(self,event):
print("Virtual Event Data: {}".format(event))
def show(self):
self.canvas.itemconfig(self.connector,state="normal")
class screen(Canvas):
width =0
height=0
cY = 0
cX = 0
items =[]
dragItem = None
mouseOverItem = None
def setScreenSize(self,width,height):
self.height = height
self.width = width
self.cX = int(width/2)
self.cY = int(height/2)
def __init__(self,root, unit,width,height):
super(screen,self).__init__(root,width=width,height=height)
self.root = root
self.width = width
self.height = height
self.setScreenSize(width,height)
self.tag_bind('DRAG_OBJECT','<ButtonPress-1>',self.onStartDrag)
self.tag_bind('DRAG_OBJECT','<ButtonRelease-1>',self.onEndDrag)
self.tag_bind('DRAG_OBJECT','<B1-Motion>',self.onDrag)
self.bind("<Configure>", self.configure)
def addObject(self,object):
self.items.append(object)
def findObject(self,tags):
for item in self.items:
if str(item.id) in tags:
return item
return None
def onStartDrag(self,event):
self.dragItem= self.find_closest(event.x,event.y)
wt = self.gettags(self.dragItem)
self.dragItem = self.findObject(wt)
def onEndDrag(self,event):
self.dragItem = None
def onDrag(self,event):
self.dragItem.move(event.x,event.y)
def draw(self):
# Draw array of items
for o in self.items:
o.show()
def translateX(self,x):
return (x + self.cX)
def translateY(self,y):
return (y + self.cY)
def translatePoint(self,pointxy):
return (self.translateX(pointxy[0]),self.translateY(pointxy[1]))
class point(Frame):
state = "normal"
x : int
y : int
def setPoint(self,x,y):
self.x = x
self.y = y
def __init__(self,canvas,x,y,radius,ObjectName):
super(point,self).__init__(canvas)
self.x = x
self.y = y
self.radius = radius
self.canvas = canvas
self.ObjectName= ObjectName
self.id = None
self.create_point()
def create_point(self):
x = self.canvas.translateX(self.x)
y = self.canvas.translateY(self.y)
self.circle = self.canvas.create_oval(x-self.radius,y-self.radius,x+self.radius,y+self.radius,state=self.state,fill='yellow')
self.text = self.canvas.create_text(x,y,text=self.ObjectName,state=self.state )
self.canvas.itemconfig(self.circle, tags=({"type":"POINT", "name":self.ObjectName},"DRAG_OBJECT"))
self.canvas.itemconfig(self.text, tags=({"type":"POINT", "name":self.ObjectName},"DRAG_OBJECT"))
self.id = {"type":"POINT", "name":self.ObjectName}
def show(self):
newX = self.canvas.translateX(self.x)
newY = self.canvas.translateY(self.y)
self.canvas.itemconfig(self.circle,state='normal')
self.canvas.coords(self.circle,(newX-self.radius,newY-self.radius,newX + self.radius, newY + self.radius))
self.canvas.coords(self.text,(newX,newY))
self.canvas.itemconfig(self.text,state='normal')
self.canvas.tag_raise(self.circle)
self.canvas.tag_raise(self.text)
def hide(self):
self.canvas.itemconfig(self.circle,state='hidden')
self.canvas.itemconfig(self.text,state='hidden')
def move (self,x,y):
delta_x = x- (self.x + self.canvas.cX)
delta_y = y- (self.y + self.canvas.cY)
self.canvas.move(self.circle,delta_x,delta_y)
self.canvas.move(self.text,delta_x,delta_y)
self.x = x - self.canvas.cX
self.y = y - self.canvas.cY
## If I use the canvas object (that is passed in) then the Point object picks up the event, but then I cant tell which 'Point' is begin dragged
#self.canvas.event_generate("<<foo>>",x=self.x,y=self.y,when='now')
## If I generate the event from the Point Object then the Event is lost
self.event_generate("<<foo>>",x=self.x,y=self.y,when='tail')
self.update()
# Start of program
print("Start --->")
tk = Tk()
mainScreen = screen(tk,20,700,700)
mainScreen.pack(fill="both",expand=1)
# Add Point A
pointA = point(mainScreen,0,0,10,"A",)
mainScreen.addObject(pointA)
# Add Point B
pointB = point(mainScreen,20,20,10,"B")
mainScreen.addObject(pointB)
LineA = pointConnector(mainScreen,pointA,pointB)
mainScreen.addObject(LineA)
mainScreen.draw()
tk.mainloop()

Related

How to acces my variable outside of my class?

I'm just starting to learn how to code, and I'm facing an issue. This is the first time I'm dealing with classes, and I have a simple program to make, but even though it is simple I'm have trouble making it work.
It is not finished, nor cleaned up so It'll look messy, but I need someone's help to move ahead.
In my code, I'm try to run a loop to creates instances of an object, and the number of instances is defined by the user in my Sousfenetre() class.
Inside that class, I have methods, including one which sets the variable 'nbrboules'
I'm trying to access its values at the end of my code, but can't seem to figure out how to.
(And if someone could explain why "nbr" Stringvar() isn't showing in "saisie" Entry widget, and why self.nbr.get() returns the wrong value, that would be nice as well :)
from tkinter import *
import random
fenetre = Tk()
fenetre.title("Boules")
fenetre.geometry("600x600")
Tx,Ty = 600,600
canvas = Canvas(fenetre,height=600,width=600,bg="yellow")
canvas.pack()
class Sousfenetre(Tk):
def __init__(self):
global label
Tk.__init__(self)
self.nbr = StringVar()
self.nbr.set("Entrez un nombre entier")
self.saisie = Entry(self, textvariable=self.nbr, width=200)
self.saisie.grid(row=0)
self.bouton = Button(self, text="VALIDER", font=(None, 30), command=self.valider)
self.bouton.grid(row=1)
self.label = Label(self, text="")
self.label.grid(row=2)
def valider(self):
global nbrboules,label
try:
nbrboules = int(self.saisie.get())
# POURQUOI SELF.NBR.GET() RENVOIE LA MAUVAISE VALEUR PUTAIN
self.destroy()
except ValueError:
self.label.config(text="Entrez un nombre entier !")
def access(self):
return self.nbrboules
class Boule():
def __init__(self):
self.x=random.randint(10,590)
self.y = random.randint(10, 590)
self.dx = random.randint(20,40)
self.dy = random.randint(20, 40)
self.r = random.randint(2,10)
def inversedx(self):
self.dx = -self.dx
def inversedy(self):
self.dy = -self.dy
def deplacementx(self):
self.x += self.dx
def deplacementy(self):
self.y += self.y
def setdx(self,param):
self.x = param
def setdy(self,param):
self.y = param
def collisionBords(self,Tx,Ty):
if self.x + self.dx > Tx - self.r or self.x + self.dx < 0 + self.r :
return self.x
if self.y + self.dy > Ty - self.r or self.y + self.dy < 0 + self.r :
return self.y
# def collisionBoule(self,boule):
# if abs(self.x - boule.x) and abs(self.y - boule.y) < self.r + boule.r:
Sousfenetre()
listeboule = []
Cercles = []
couleur = ["blue","red","green"]
listeboule.append(Boule())
listeboule.append(Boule())
listeboule.append(Boule())
listeboule.append(Boule())
listeboule.append(Boule())
listeboule.append(Boule())
listeboule.append(Boule())
listeboule.append(Boule())
listeboule.append(Boule())
listeboule.append(Boule())
listeboule.append(Boule())
listeboule.append(Boule())
#I know this isn't efficient, it was for testing purposes
f = Sousfenetre()
for i in range(0,f.access()):
Cercles.append(canvas.create_oval(listeboule[i].x-listeboule[i].r,listeboule[i].y-listeboule[i].r,listeboule[i].x+listeboule[i].r,listeboule[i].y+listeboule[i].r,fill=random.choice(couleur)))
print(listeboule)
def test():
print(nbrboules)
fenetre.mainloop()
This code works for me.
It uses Toplevel to creates Sousfenetre so Entry displays text from self.nbr.
Because mainloop starts program so everything before mainloop is executed before you press button. I sends listeboule, cercles to Sousfenetre as parameters and it can use them in valider when you press button.
I also used fenetre.after(100, f.lift) to move Sousfenetre to the front 100ms after creating main window so it is not hidden behind main window.
import tkinter as tk # `import *` is not preferred
import random
# --- classes ---
class Sousfenetre(tk.Toplevel):
def __init__(self, listeboule, cercles):
super().__init__() # in Python 3 you can use `super()` instead of class name
# remeber as class variable to have access in other methods
self.listeboule = listeboule
self.cercles = cercles
self.nbr = tk.StringVar()
self.nbr.set("Entrez un nombre entier")
self.saisie = tk.Entry(self, textvariable=self.nbr)
self.saisie.grid(row=0)
self.bouton = tk.Button(self, text="VALIDER", command=self.valider)
self.bouton.grid(row=1)
self.label = tk.Label(self, text="")
self.label.grid(row=2)
def valider(self):
try:
nbrboules = int(self.saisie.get())
# uses
for i in range(nbrboules):
b = self.listeboule[i]
c = random.choice(couleur)
self.cercles.append(canvas.create_oval(b.x-b.r, b.y-b.r, b.x+b.r, b.y+b.r, fill=c))
self.destroy()
except ValueError:
self.label.config(text="Entrez un nombre entier !")
class Boule():
def __init__(self):
self.x = random.randint(10,590)
self.y = random.randint(10, 590)
self.dx = random.randint(20,40)
self.dy = random.randint(20, 40)
self.r = random.randint(2,10)
def inversedx(self):
self.dx = -self.dx
def inversedy(self):
self.dy = -self.dy
def deplacementx(self):
self.x += self.dx
def deplacementy(self):
self.y += self.y
def setdx(self,param):
self.x = param
def setdy(self,param):
self.y = param
def collisionBords(self,Tx,Ty):
if self.x + self.dx > Tx - self.r or self.x + self.dx < 0 + self.r :
return self.x
if self.y + self.dy > Ty - self.r or self.y + self.dy < 0 + self.r :
return self.y
# --- functions ---
# empty
# --- main ---
#listeboule = []
#for _ in range(12):
# listeboule.append(Boule())
listeboule = [Boule() for _ in range(12)] # create 12 circles
cercles = []
couleur = ["blue", "red", "green"]
Tx = 600
Ty = 600
# ---
fenetre = tk.Tk()
fenetre.title("Boules")
fenetre.geometry("600x600")
canvas = tk.Canvas(fenetre, height=600, width=600, bg="yellow")
canvas.pack()
# send `listeboule`, `cercles` to class
f = Sousfenetre(listeboule, cercles)
# Move `Sousfenetre` to the front 100ms after creating main window.
# This way Sousfenetre is not hidden behind main window.
fenetre.after(100, f.lift)
# start program
fenetre.mainloop()

tkinter - problem with a coloring a rectangle in a grid made out of rectangles

I am trying to write a pathfinding algorithm in python. The user is supposed to select a starting point by hovering the mouse of a field and pressing s. The field should now change the color.
However, I can't figure out what is wrong with my code. I am only able to color to color the fields from top left corner to the bottom right corner. In the code, Im printing out the objectID in console, which shows that there is maybe something wrong with the way of how I created the rectangles.
I'm creating the rectangles in the draw_grid method in the Window class and coloring the fields in the select_start_node method.
import tkinter as tk
class Window:
def __init__(self):
self.height = 600
self.width = 600
self.grid_list = {x for x in range(0, 600)}
self.grid = []
self.grid_dict = {}
self.root = tk.Tk()
self.root.geometry("600x600")
self.root.resizable(False, False)
self.canvas = tk.Canvas(self.root, width=self.width,
height=self.height, background="white")
self.canvas.bind("s", self.select_start_node)
self.canvas.bind("<1>", lambda event:
self.canvas.focus_set())
def draw_grid(self):
print(self.grid)
for x in self.grid_list:
if x % 30 == 0:
self.grid.append(x)
else:
pass
print(self.grid)
for x in self.grid:
for y in self.grid:
print(x, y+30)
rec = self.canvas.create_rectangle(x, x, y+30, y+30)
self.canvas.pack()
def select_start_node(self, event):
print(event.x, event.y)
x = self.canvas.canvasx(event.x)
y = self.canvas.canvasy(event.y)
item = self.canvas.find_closest(x, y)
p = self.canvas.coords(item)
print(item)
print(p)
self.canvas.create_rectangle(p[0], p[0], p[0]+30, p[0]+30, fill="red")
def main():
node_list = []
cord_list = []
window = Window()
window.draw_grid()
window.root.mainloop()
if __name__ == "__main__":
main()
I don't know the entire design of you game, but suggest that you do things differently with respect to the grid of rectangles. In the code below self.grid is a 2-dimensional list-of-lists and each entry is a Canvas rectangle object. This make selecting and changing one of them relatively each because canvas.find_closest(x, y) will give you the object id of the associated rectangle object directly, which makes changing its fill color trivial.
Because of that, I also changed it so you can just click on one of the rectangles to change it instead of moving the mouse cursor and then pressing a key.
Also note that I also got rid of most those hardcoded numerical constants you were using all over the place, which makes the code more flexible in case you decide to change one of them at a later time.
import tkinter as tk
class Window:
def __init__(self):
self.cell_size = 30
self.height = 600
self.width = 600
self.hz_cells = self.width // self.cell_size # Number of horizontal cells.
self.vt_cells = self.height // self.cell_size # Number of vertical cells.
# Preallocate 2D grid (list-of-lists).
self.grid = [[None for _ in range(self.hz_cells)]
for _ in range(self.vt_cells)]
self.root = tk.Tk()
self.root.geometry("%sx%s" % (self.width, self.height))
self.root.resizable(False, False)
self.canvas = tk.Canvas(self.root, width=self.width,
height=self.height, background="white")
self.canvas.pack()
self.canvas.bind("<1>", self.select_start_node)
# You can still do it this way if you want.
# self.canvas.bind("s", self.select_start_node)
# self.canvas.bind("<1>", lambda event: self.canvas.focus_set())
def draw_grid(self):
""" Fill Canvas with a grid of white rectangles. """
for i in range(self.hz_cells):
x = i * self.cell_size
for j in range(self.vt_cells):
y = j * self.cell_size
self.grid[i][j] = self.canvas.create_rectangle(
x, y, x+self.cell_size, y+self.cell_size, fill="white")
def select_start_node(self, event):
""" Change the color of the rectangle closest to x, y of event. """
x = self.canvas.canvasx(event.x)
y = self.canvas.canvasy(event.y)
selected_rect = self.canvas.find_closest(x, y)
if selected_rect:
self.canvas.itemconfigure(selected_rect, fill="red") # Change color.
def main():
node_list = []
cord_list = []
window = Window()
window.draw_grid()
window.root.mainloop()
if __name__ == "__main__":
main()

The item configure method didn't work in Tkinter

I tried to use the Tkinter library for my small project in python. I create a 500 by 500 square with 10000 small square in it.
And I want each small square turns black when user click on it. Can someone please tell me why, I would really appreciate it. Here is the graphics code:
from Tkinter import *
from button import *
class AppFrame(Frame):
def __init__(self):
self.root = Tk()
self.root.geometry = ("1000x1000")
self.f = Frame(self.root, relief = 'sunken', width = 600, height = 600)
self.w = Canvas(self.f,width = 505, height =505)
##get the x, y value whenever the user make a mouse click
self.w.bind("<Button-1>", self.xy)
self.bolist = []
for k in range(1,101):
for i in range(1, 101):
button = Buttons(self.w, i * 5, k * 5, i * 5 + 5, k * 5 + 5)
self.bolist.append(button)
self.f.grid(column =0, columnspan = 4)
self.w.grid(column = 0)
self.root.mainloop()
def xy (self, event):
self.x, self.y = event.x, event.y
print (self.x, self.y)
##check each button if it's clicked
for hb in self.bolist:
if hb.clicked(self.x, self.y):
print ("hurry")
hb.activate()
And
##button.py
from Tkinter import *
class Buttons:
def __init__(self,canvas,bx,by,tx,ty):
self.canvas = canvas
self.rec = canvas.create_rectangle((bx,by,tx,ty),fill = "lightgray",
activefill= 'black', outline = 'lightgray')
self.xmin = bx
self.xmax = tx
self.ymin = by
self.ymax = ty
##print (bx, by, tx, ty)
def clicked(self, px, py):
return (self.active and self.xmin <= px <= self.xmax and
self.ymin <= py <= self.ymax)
def activate(self):
self.canvas.itemconfigure(slef.rec, fill = 'black')
self.active = True
The problem is that you don't initialize the active attribute, so it doesn't exist until the cell becomes active. To fix that, add self.active = False inside the __init__ method of Buttons.
You also have a typo in this line (notice you use slef rather than self):
self.canvas.itemconfigure(slef.rec, fill = 'black')
Instead of a global binding on the canvas, it would be more efficient to set a binding on each individual rectangle. You can then use the binding to pass the instance of the Buttons class to the callback. This way you don't have to iterate over several thousand widgets looking for the one that was clicked on.
To do this, use the tag_bind method of the canvas. You can make it so that your main program passes in a reference to a function to call when the rectangle is clicked, then the binding can call that method and pass it a reference to itself.
For example:
class Buttons:
def __init__(self,canvas,bx,by,tx,ty, callback):
...
self.rec = canvas.create_rectangle(...)
self.canvas.tag_bind(self.rec, "<1>",
lambda event: callback(self))
...
class AppFrame(Frame):
def __init__(...):
...
button = Buttons(..., self.callback)
...
def callback(self, b):
b.activate()
Here, I looked at your code, debugged it, and made some adjustments. It works now.
Just keep both the scripts in one folder and run your AppFrame script (the second one in this answer)
##button.py
from Tkinter import *
class Buttons:
def __init__(self,canvas,bx,by,tx,ty):
self.canvas = canvas
self.rec = canvas.create_rectangle((bx,by,tx,ty),fill = "lightgray", activefill= 'black', outline = 'lightgray')
self.xmin = bx
self.xmax = tx
self.ymin = by
self.ymax = ty
##print (bx, by, tx, ty)
def clicked(self, px, py):
return (self.xmin <= px <= self.xmax and
self.ymin <= py <= self.ymax)
def activate(self):
self.canvas.itemconfigure(self.rec, fill = 'black')
AND
from Tkinter import *
from button import *
class AppFrame(Frame):
def __init__(self):
self.root = Tk()
self.root.geometry = ("1000x1000")
self.f = Frame(self.root, relief = 'sunken', width = 600, height = 600)
self.w = Canvas(self.f,width = 505, height =505)
##get the x, y value whenever the user make a mouse click
self.w.bind("<Button-1>", self.xy)
self.bolist = []
for k in range(1,101):
for i in range(1, 101):
button = Buttons(self.w, i * 5, k * 5, i * 5 + 5, k * 5 + 5)
self.bolist.append(button)
self.f.grid(column =0, columnspan = 4)
self.w.grid(column = 0)
self.root.mainloop()
def xy (self, event):
self.x, self.y = event.x, event.y
print (self.x, self.y)
##check each button if it's clicked
for hb in self.bolist:
if hb.clicked(self.x, self.y):
print ("hurry")
hb.activate()
newApp = AppFrame()

Quick debugging question [Python, pygame]

It's still an incomplete program, but for some reason the value of the textbox doesn't increase when it should... Why is this??
When the Pizza sprite overlaps with the Pan sprite, the score in the textbox is supposed to increase in value by 10. Why does this not occur?
Thanks!
'''
Created on Jul 1, 2011
#author: ******* Louis
'''
#Watch me do.
from livewires import games, color
import random
games.init (screen_width = 640, screen_height = 480, fps = 50)
#Pizza Class
class Pizza (games.Sprite):
pizzaimage = games.load_image ("pizza.bmp", transparent = True)
def __init__(self, x = random.randrange(640), y = 90, dy = 4):
super (Pizza, self).__init__(x = x,
y = y,
image = Pizza.pizzaimage,
dy = dy)
def handle_caught (self):
self.destroy()
class Pan (games.Sprite):
panimage = games.load_image ("pan.bmp", transparent = True)
def __init__ (self, x = games.mouse.x, y = games.mouse.y):
super (Pan, self).__init__(x = x,
y = y,
image = Pan.panimage)
self.score = 0
self.textbox = games.Text (value = str(self.score),
size = 20,
color = color.black,
x = 550,
y = 50)
games.screen.add(self.textbox)
def update (self): #WWWWOW There is actually an *update* method
self.x = games.mouse.x
self.y = games.mouse.y
if self.left < 0:
self.left = 0
if self.right >640:
self.right = 640
if self.top < 0:
self.top = 0
if self.bottom > 480:
self.bottom = 480
self.check_collision()
def check_collision (self):
for Pizza in self.overlapping_sprites:
self.score = self.score + 10
Pizza.handle_caught()
#main
def main():
wallbackground = games.load_image ("wall.jpg", transparent = False)
games.screen.background = wallbackground
games.screen.add(Pizza())
games.screen.add(Pan())
games.mouse.is_visible = False
games.screen.event_grab = True
games.screen.mainloop()
main()
The textbox takes a value that is a string. When you create the textbox, you create a string from the current value of score, and set the text to that string. No lasting connection between score and textbox is made.
The textbox probably has a method available to update its text; call that method with the value str(self.score) after you increment the score.

How to draw the "trail" in a maze solving application

Hello i have designed a maze and i want to draw a path between the cells as the 'person' moves from one cell to the next.
So each time i move the cell a line is drawn
Also i am using the graphics module
The graphics module is an object oriented library
Im importing
from graphics import*
from maze import*
my circle which is my cell
center = Point(15, 15)
c = Circle(center, 12)
c.setFill('blue')
c.setOutline('yellow')
c.draw(win)
p1 = Point(c.getCenter().getX(), c.getCenter().getY())
this is my loop
if mazez.blockedCount(cloc)> 2:
mazez.addDecoration(cloc, "grey")
mazez[cloc].deadend = True
c.move(-25, 0)
p2 = Point(p1.getX(), p1.getY())
line = graphics.Line(p1, p2)
cloc.col = cloc.col - 1
Now it says getX not defined every time i press a key is this because of p2???
This is the most important bits in the module for this part
def __init__(self, title="Graphics Window",
width=200, height=200, autoflush=True):
master = tk.Toplevel(_root)
master.protocol("WM_DELETE_WINDOW", self.close)
tk.Canvas.__init__(self, master, width=width, height=height)
self.master.title(title)
self.pack()
master.resizable(0,0)
self.foreground = "black"
self.items = []
self.mouseX = None
self.mouseY = None
self.bind("<Button-1>", self._onClick)
self.height = height
self.width = width
self.autoflush = autoflush
self._mouseCallback = None
self.trans = None
self.closed = False
master.lift()
if autoflush: _root.update()
def __checkOpen(self):
if self.closed:
raise GraphicsError("window is closed")
def setCoords(self, x1, y1, x2, y2):
"""Set coordinates of window to run from (x1,y1) in the
lower-left corner to (x2,y2) in the upper-right corner."""
self.trans = Transform(self.width, self.height, x1, y1, x2, y2)
def plot(self, x, y, color="black"):
"""Set pixel (x,y) to the given color"""
self.__checkOpen()
xs,ys = self.toScreen(x,y)
self.create_line(xs,ys,xs+1,ys, fill=color)
self.__autoflush()
def plotPixel(self, x, y, color="black"):
"""Set pixel raw (independent of window coordinates) pixel
(x,y) to color"""
self.__checkOpen()
self.create_line(x,y,x+1,y, fill=color)
self.__autoflush()
def draw(self, graphwin):
if self.canvas and not self.canvas.isClosed(): raise GraphicsError(OBJ_ALREADY_DRAWN)
if graphwin.isClosed(): raise GraphicsError("Can't draw to closed window")
self.canvas = graphwin
self.id = self._draw(graphwin, self.config)
if graphwin.autoflush:
_root.update()
def move(self, dx, dy):
"""move object dx units in x direction and dy units in y
direction"""
self._move(dx,dy)
canvas = self.canvas
if canvas and not canvas.isClosed():
trans = canvas.trans
if trans:
x = dx/ trans.xscale
y = -dy / trans.yscale
else:
x = dx
y = dy
self.canvas.move(self.id, x, y)
if canvas.autoflush:
_root.update()
class Point(GraphicsObject):
def __init__(self, x, y):
GraphicsObject.__init__(self, ["outline", "fill"])
self.setFill = self.setOutline
self.x = x
self.y = y
def _draw(self, canvas, options):
x,y = canvas.toScreen(self.x,self.y)
return canvas.create_rectangle(x,y,x+1,y+1,options)
def _move(self, dx, dy):
self.x = self.x + dx
self.y = self.y + dy
def clone(self):
other = Point(self.x,self.y)
other.config = self.config.copy()
return other
def getX(self): return self.x
def getY(self): return self.y
def __init__(self, p1, p2, options=["outline","width","fill"]):
GraphicsObject.__init__(self, options)
self.p1 = p1.clone()
self.p2 = p2.clone()
def _move(self, dx, dy):
self.p1.x = self.p1.x + dx
self.p1.y = self.p1.y + dy
self.p2.x = self.p2.x + dx
self.p2.y = self.p2.y + dy
def getP1(self): return self.p1.clone()
def getP2(self): return self.p2.clone()
def getCenter(self):
p1 = self.p1
p2 = self.p2
return Point((p1.x+p2.x)/2.0, (p1.y+p2.y)/2.0)
You might try this from an interactive Python shell:
>>> import graphics
>>> help(graphics.Circle)
That should tell you what attributes Circle does have.
You're trying to use getX() and getY() as free-standing FUNCTIONS:
p2 = Point(getX(), getY())
Note that you're calling them as bare names, not qualified names -- therefore, as functions, not as methods.
And yet the docs you quote say they're methods -- therefore, they must be called as part of qualified names ("after a dot"...!-) and before the dot must be an instance of Point.
Presumably, therefore, you need p1.getX() and p1.getY() instead of the bare names you're using. p1.getX is a qualified name (i.e., one with a dot) and it means "method or attribute getX of object p1.
This is really super-elementary Python, and I recommend you first study the official Python tutorial or other even simpler introductory documents before you try making or modifying applications in Python.
I don't know how maze solves the puzzle, so I am going to assume it works like a generator, yielding the next move for the circle to make. Something to this effect:
while not this_maze.solved():
next_position = this_maze.next()
my_circle.move(next_position)
Then all you need to do is keep track of the current circle position and the previous circle position.
prev_position = this_maze.starting_point
while not this_maze.solved():
next_position = this_maze.next()
my_circle.clear()
draw_trail(prev_position, next_position)
my_circle.draw_at(next_position)
prev_position = next_position
Obviously, changing this in something compatible with your framework is left up to you. dir(), help() and reading the libraries' source will all help you.

Categories