I'm tying to create a basic program for drawing to the screen by creating ovals every frame when the mouse is clicked. However, as the program runs for a bit, it starts becoming very choppy and the circles stop forming cohesive lines, due to the code not running fast enough to process precise mouse movement.
Here is my code -
import tkinter as tk
DRAW_HEIGHT = 560
DRAW_WIDTH = 560
PALETTE_HEIGHT = 40
def draw_palette(canvas):
canvas.create_rectangle(0, 0, DRAW_WIDTH, PALETTE_HEIGHT, fill = 'light grey', width= 0)
canvas.create_rectangle(DRAW_WIDTH/8, PALETTE_HEIGHT/5, 3*DRAW_WIDTH/8, 4*PALETTE_HEIGHT/5, fill = 'dark grey', width = 1)
canvas.create_rectangle(5*DRAW_WIDTH/8, PALETTE_HEIGHT/5, 7*DRAW_WIDTH/8, 4*PALETTE_HEIGHT/5, fill = 'dark grey',width = 1)
canvas.create_text(DRAW_WIDTH/4, PALETTE_HEIGHT/2, text = 'clear screen') #non-functional
class Brush():
def __init__(self,stroke_size,stroke_color):
self.size = stroke_size
self.color = stroke_color
self.mode = 'draw'
self.pos = (0,0)
self.clicked = False
def render(self,canvas):
if self.clicked:
canvas.create_oval( self.pos.x-self.size/2, self.pos.y-self.size/2,
self.pos.x+self.size/2, self.pos.y+self.size/2,
width = 0, fill = self.color )
def mouse_moved(self,event):
self.pos = event
def mouse_clicked(self,throwaway):
self.clicked = True
def mouse_released(self,throwaway):
self.clicked = False
#set up root window and canvas
root = tk.Tk()
root.geometry('{}x{}'.format(DRAW_WIDTH,DRAW_HEIGHT+PALETTE_HEIGHT))
c = tk.Canvas(root, width = DRAW_WIDTH, height = DRAW_HEIGHT + PALETTE_HEIGHT, bg = 'white')
c.pack()
b = Brush(40,'black')
#bind actions to functions
c.bind("<Button-1>",b.mouse_clicked)
c.bind("<ButtonRelease-1>",b.mouse_released)
c.bind("<Motion>",b.mouse_moved)
#main loop
while 1:
b.render(c)
draw_palette(c)
root.update()
I suppose I'm just asking if there's any way I can speed this up, but specifically I'm wondering if I can draw the shapes to the screen without using create_shape() every time.
For example,
oval = c.create_oval()
while 1:
canvas.draw(oval)
I know you can do something similar with canvas.move(), but I couldn't find anything that fit my situation.
I don't understand why you created loop while 1 and run render() and draw_palette() hundreds of times even if you don't need it.
I draw new circle in mouse_moved() and use root.mainloop() and it runs much better and create smoother line. Probably if I would draw line from previous place to current place or many ovals with some step then I would get even better line
EDIT: I changed little to draw first oval in mouse_click() - so I can see first oval even if I only click and don't move.
import tkinter as tk
# --- constanst ---
DRAW_HEIGHT = 560
DRAW_WIDTH = 560
PALETTE_HEIGHT = 40
# --- classes ---
class Brush():
def __init__(self,stroke_size,stroke_color):
self.size = stroke_size
self.color = stroke_color
self.mode = 'draw'
self.pos = (0,0)
self.clicked = False
def draw(self):
s = self.size/2
c.create_oval(
self.pos.x-s, self.pos.y-s,
self.pos.x+s, self.pos.y+s,
width=0, fill=self.color
)
def mouse_moved(self, event):
if self.clicked:
self.pos = event
self.draw()
def mouse_clicked(self, event):
self.clicked = True
self.pos = event
self.draw()
def mouse_released(self, event):
self.clicked = False
# --- functions ---
def draw_palette(canvas):
canvas.create_rectangle(0, 0, DRAW_WIDTH, PALETTE_HEIGHT, fill='light grey', width=0)
canvas.create_rectangle(DRAW_WIDTH/8, PALETTE_HEIGHT/5, 3*DRAW_WIDTH/8, 4*PALETTE_HEIGHT/5, fill='dark grey', width=1)
canvas.create_rectangle(5*DRAW_WIDTH/8, PALETTE_HEIGHT/5, 7*DRAW_WIDTH/8, 4*PALETTE_HEIGHT/5, fill='dark grey', width=1)
canvas.create_text(DRAW_WIDTH/4, PALETTE_HEIGHT/2, text='clear screen') #non-functional
# --- main ---
#set up root window and canvas
root = tk.Tk()
root.geometry('{}x{}'.format(DRAW_WIDTH, DRAW_HEIGHT+PALETTE_HEIGHT))
c = tk.Canvas(root, width=DRAW_WIDTH, height=DRAW_HEIGHT+PALETTE_HEIGHT, bg='white')
c.pack()
b = Brush(40, 'black')
#bind actions to functions
c.bind("<Button-1>", b.mouse_clicked)
c.bind("<ButtonRelease-1>", b.mouse_released)
c.bind("<Motion>", b.mouse_moved)
draw_palette(c)
root.mainloop()
EDIT:
I added function which adds ovals if distance between previous and current position is too big and there is gap. Now line is smooth even if mouse moves fast.
import tkinter as tk
# --- constanst ---
DRAW_HEIGHT = 560
DRAW_WIDTH = 560
PALETTE_HEIGHT = 40
# --- classes ---
class Brush():
def __init__(self,stroke_size,stroke_color):
self.size = stroke_size
self.color = stroke_color
self.mode = 'draw'
self.pos = None
self.prev = None
self.clicked = False
def draw_oval(self, x, y):
r = self.size/2 # radius
c.create_oval(x-r, y-r, x+r, y+r, width=0, fill=self.color)
def draw(self):
if self.pos:
self.draw_oval(self.pos.x, self.pos.y)
if self.prev:
# calculate distance between ovals
dx = self.pos.x - self.prev.x
dy = self.pos.y - self.prev.y
max_diff = max(abs(dx), abs(dy))
# add ovals if distance bigger then some size of oval (tested with //4, //8, //6, //5)
if max_diff > (self.size//6):
# how many ovals to add
parts = max_diff//(self.size//6)
# distance between ovals
step_x = dx/parts
step_y = dy/parts
# add ovals except first which is already on canvas
for i in range(1, parts):
x = self.pos.x - i*step_x
y = self.pos.y - i*step_y
self.draw_oval(x, y)
def mouse_moved(self, event):
if self.clicked:
self.prev = self.pos
self.pos = event
self.draw()
def mouse_clicked(self, event):
self.clicked = True
self.prev = None
self.pos = event
self.draw()
def mouse_released(self, event):
self.clicked = False
self.prev = None
self.pos = None
# --- functions ---
def draw_palette(canvas):
canvas.create_rectangle(0, 0, DRAW_WIDTH, PALETTE_HEIGHT, fill='light grey', width=0)
canvas.create_rectangle(DRAW_WIDTH/8, PALETTE_HEIGHT/5, 3*DRAW_WIDTH/8, 4*PALETTE_HEIGHT/5, fill='dark grey', width=1)
canvas.create_rectangle(5*DRAW_WIDTH/8, PALETTE_HEIGHT/5, 7*DRAW_WIDTH/8, 4*PALETTE_HEIGHT/5, fill='dark grey', width=1)
canvas.create_text(DRAW_WIDTH/4, PALETTE_HEIGHT/2, text='clear screen') #non-functional
# --- main ---
#set up root window and canvas
root = tk.Tk()
root.geometry('{}x{}'.format(DRAW_WIDTH, DRAW_HEIGHT+PALETTE_HEIGHT))
c = tk.Canvas(root, width=DRAW_WIDTH, height=DRAW_HEIGHT+PALETTE_HEIGHT, bg='white')
c.pack()
b = Brush(40, 'black')
#bind actions to functions
c.bind("<Button-1>", b.mouse_clicked)
c.bind("<ButtonRelease-1>", b.mouse_released)
c.bind("<Motion>", b.mouse_moved)
draw_palette(c)
root.mainloop()
Related
Here is the code, I have managed to position the square a little bit but the whole thing is just messy and fast when executed, it doesn't really resemble anything, let alone what I wanted to make.
What do I need to do in order to get these 4 squares to start in the middle and move to each corner, disappearing from the screen? I made an example here:
from tkinter import *
W, H = 500, 500
tk = Tk()
canvas = Canvas(tk,width=W,height=H)
canvas.pack()
class Square:
def __init__(self,size,speedx, speedy, color):
self.square = canvas.create_rectangle(50,50,100,100,fill=color)
self.speedx = speedx
self.speedy = speedy
self.movement()
def movement(self):
canvas.move(self.square,self.speedx,self.speedy)
pos = canvas.coords(self.square)
if pos[2]>=W or pos[0]<=0:
self.speedx *= -1
if pos[3]>=H or pos[1]<=0:
self.speedy *= -1
tk.after(40,self.movement)
square1 = Square(200,150,200,'brown')
square2 = Square(200,200,150,'yellow')
square3 = Square(200,200,200,'green')
square4 = Square(200,150,150,'blue')
tk.mainloop()
You need to define direction for each rectangle separately, so that each of them moves its own way.
import tkinter as tk
W, H = 500, 500
SPEED = 20
window = tk.Tk()
canvas = tk.Canvas(window, width=W, height=H)
canvas.pack()
class Square:
def __init__(self, x, y, color, speed_x, speed_y):
self.speed_x = speed_x
self.speed_y = speed_y
self.square = canvas.create_rectangle(x, y, x+50, y+50, fill=color)
self.movement()
def movement(self):
canvas.move(self.square, self.speed_x, self.speed_y)
window.after(200, self.movement)
Square(200, 200, 'brown', -SPEED, -SPEED)
Square(250, 200, 'yellow', SPEED, -SPEED)
Square(200, 250, 'green', -SPEED, SPEED)
Square(250, 250, 'blue', SPEED, SPEED)
window.mainloop()
Output:
import time
from tkinter import *
import random
class SpaceField:
def __init__(self):
self.window = Tk()
self.window.title("Asteriods")
self.canvas = self.canvas_display() #creates canvas
self.asteriods = self.asteriod_creation_seperation() #creates asteroids
self.active = True
self.move_active() #Moves asteroids
self.canvas.update()
def asteriod_creation_seperation(self): #creation of multple asteriods
asteriod_spacingx = random.randint(1,800)
asteriod_spacingy = random.randint(1,800)
asteriod_list = list() # could list([])
for i in range(15):
asteriod = self.canvas.create_oval( 30, 50 , 80 , 100 , tags="asteriod", width=2, outline="white")
asteriod_list.append("asteriod")
self.canvas.move(asteriod, asteriod_spacingx, asteriod_spacingy)
asteriod_spacingx = random.randint(1,500)
asteriod_spacingy = random.randint(1,500)
print(asteriod_spacingy)
return asteriod_list
Asteroid Creation. Creates asteroids and gives them random positions.
def asteriod_update(self): #asteriods movement method #MAin problem
x12 = 1
self.canvas.move("asteriod", 3, x12)
pos = self.canvas.coords("asteriod")
print(pos)
if (pos)[2] > 500:
x12 *= 5
I think this is where I need to add the collision detection. I just have no idea how to combine the lists of the circles and the collisions.
def move_active(self): #Basically a true loop
if self.active:
self.asteriod_update()
self.window.after(40, self.move_active)
def canvas_display(self): #canvas
canvas = Canvas(self.window, width=500, height=400, background='black')
canvas.pack(expand=True, fill="both")
canvas.update()
return canvas
Canvas display nothing special
def run(self):
self.window.mainloop()
if __name__ == '__main__':
SpaceF = SpaceField()
SpaceF.run()
Asteroids is a classic game but there were a number of problems in your code. The main one was calling move_active during initialization. This prevented the code from completing its mainloop initialization.
The other problem was the asteroid_update method that basically didn't do anything, also using tags to control all asteroids didn't work either.
Everything else was OK, although you might consider using polygons.
Here is one way to produce a bouncing objects program. I've inserted remarks that describe the methods used.
Objects change the speed and direction when they hit the boundary so their trajectories are randomized.
from tkinter import *
from random import randint as rnd
class SpaceField:
def __init__(self):
self.window = Tk()
self.window.title("Asteriods")
# Define canvas size and active flag
self.wide, self.high, self.active = 500, 400, True
self.canvas_display()
self.asteriod_creation_seperation()
def asteriod_creation_seperation(self):
self.asteroids, self.speed = [], []
size, radius = 50, 25
for i in range(15):
spacex = rnd(size, self.wide - size)
spacey = rnd(size, self.high - size)
self.asteroids.append( # Store oval item id
self.canvas.create_oval(
spacex, spacey, spacex+size, spacey+size,
width=2, tags = "asteriod", outline = "white"))
self.speed.append((rnd(1,4),rnd(1,4))) # Store random speed x, y
def asteriod_update(self): # MAIN DRIVER: Work on ALL asteroids
for i, a in enumerate(self.asteroids):
xx, yy = self.speed[i] # get speed data
x, y, w, h = self.canvas.coords(a)
# check for boundary hit then change direction and speed
if x < 0 or w > self.wide:
xx = -xx * rnd(1, 4)
if y < 0 or h > self.high:
yy = -yy * rnd(1, 4)
# Limit max and min speed then store it
self.speed[i] = (max( -4, min( xx, 4)), max( -4, min( yy, 4 )))
self.canvas.move(a, xx, yy) # update asteroid position
def move_active(self):
if self.active:
self.asteriod_update()
self.window.after(40, self.move_active)
def canvas_display(self):
self.canvas = Canvas(
self.window, width = self.wide,
height = self.high, background = "black")
self.canvas.pack(expand = True, fill = "both")
def run(self): # Begin asteroids here so that mainloop is executed
self.window.after(200, self.move_active)
self.window.mainloop()
if __name__ == "__main__":
SpaceF = SpaceField()
SpaceF.run()
I am writing a simple program in which I want the (ball image png) to bounce off the walls. So far, I have writen this code:
import tkinter as tk
root = tk.Tk()
WIDTH = 500
HEIGHT = 500
canvas = tk.Canvas(root,bg="white",width=WIDTH,height=HEIGHT)
canvas.pack()
img = tk.PhotoImage(file="images/ball1.png")
ball = canvas.create_image(0,0,anchor="nw",image=img)
yspeed = 2
xspeed = 2
def move_ball():
global xspeed,yspeed,ball
canvas.move(ball,xspeed,yspeed)
canvas.after(10,move_ball)
move_ball()
root.mainloop()
You can get the current position with the coords method, then code in a check for each of the 4 walls. Here's the first one:
def move_ball():
global xspeed,yspeed,ball
xpos, ypos = canvas.coords(ball)
if xpos + width_of_ball > WIDTH:
# ball hit the right edge, reverse x direction
xspeed *= -1
canvas.move(ball,xspeed,yspeed)
canvas.after(10,move_ball)
This answer is the same thing as #Novel answer (even though I wrote it before I saw theirs). The only difference is in the fact that the logic of update doesn't expect you to make any edits for it to work, it considers both horizontal and vertical directions, and resizing the main window is compensated for.
import tkinter as tk
root = tk.Tk()
root.title('Infinite Bounce Simulator')
root.geometry('400x300+300+300')
xspeed = 4
yspeed = 3
canvas = tk.Canvas(root, highlightthickness=0, bg='#111')
canvas.pack(expand=True, fill='both')
ball = canvas.create_oval((0, 0, 20, 20), fill='red')
def update():
global xspeed, yspeed, ball
canvas.move(ball, xspeed, yspeed)
#Left, Top, Right, Bottom coordinates
l, t, r, b = canvas.coords(ball)
#flip speeds when edges are reached
if r > canvas.winfo_width() or l < 0:
xspeed = -xspeed
if b > canvas.winfo_height() or t < 0:
yspeed = -yspeed
#do it all again in 10 milliseconds
root.after(10, update)
root.after_idle(update)
root.mainloop()
I've updated the initial script with a modified version of Bryan-Oakley's answer. It now has 2 canvas, 1 with the draggable rectangle, and 1 with the plot. I would like the rectangle to be dragged along the x-axis on the plot if that is possible?
import tkinter as tk # python 3
# import Tkinter as tk # python 2
import numpy as np
from matplotlib.backends.backend_tkagg import (
FigureCanvasTkAgg, NavigationToolbar2Tk)
# Implement the default Matplotlib key bindings.
from matplotlib.backend_bases import key_press_handler
from matplotlib.figure import Figure
class Example(tk.Frame):
"""Illustrate how to drag items on a Tkinter canvas"""
def __init__(self, parent):
tk.Frame.__init__(self, parent)
fig = Figure(figsize=(5, 4), dpi=100)
t = np.arange(0, 3, .01)
fig.add_subplot(111).plot(t, 2 * np.sin(2 * np.pi * t))
#create a canvas
self.canvas = tk.Canvas(width=200, height=300)
self.canvas.pack(fill="both", expand=True)
canvas = FigureCanvasTkAgg(fig, master=root) # A tk.DrawingArea.
canvas.draw()
canvas.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, expand=1)
# this data is used to keep track of an
# item being dragged
self._drag_data = {"x": 0, "y": 0, "item": None}
# create a movable object
self.create_token(100, 150, "black")
# add bindings for clicking, dragging and releasing over
# any object with the "token" tag
self.canvas.tag_bind("token", "<ButtonPress-1>", self.drag_start)
self.canvas.tag_bind("token", "<ButtonRelease-1>", self.drag_stop)
self.canvas.tag_bind("token", "<B1-Motion>", self.drag)
def create_token(self, x, y, color):
"""Create a token at the given coordinate in the given color"""
self.canvas.create_rectangle(
x - 5,
y - 100,
x + 5,
y + 100,
outline=color,
fill=color,
tags=("token",),
)
def drag_start(self, event):
"""Begining drag of an object"""
# record the item and its location
self._drag_data["item"] = self.canvas.find_closest(event.x, event.y)[0]
self._drag_data["x"] = event.x
self._drag_data["y"] = event.y
def drag_stop(self, event):
"""End drag of an object"""
# reset the drag information
self._drag_data["item"] = None
self._drag_data["x"] = 0
self._drag_data["y"] = 0
def drag(self, event):
"""Handle dragging of an object"""
# compute how much the mouse has moved
delta_x = event.x - self._drag_data["x"]
delta_y = 0
# move the object the appropriate amount
self.canvas.move(self._drag_data["item"], delta_x, delta_y)
# record the new position
self._drag_data["x"] = event.x
self._drag_data["y"] = event.y
if __name__ == "__main__":
root = tk.Tk()
Example(root).pack(fill="both", expand=True)
root.mainloop()
Any help is greatly appreciated.
The issue with your code is that you create two canvases, one for the matplotlib figure and one for the draggable rectangle while you want both on the same.
To solve this, I merged the current code of the question with the one before the edit, so the whole matplotlib figure is now embedded in the Tkinter window. The key modification I made to the DraggableLine class is that it now takes the canvas as an argument.
import tkinter as tk # python 3
# import Tkinter as tk # python 2
import numpy as np
import matplotlib.lines as lines
from matplotlib.backends.backend_tkagg import (
FigureCanvasTkAgg, NavigationToolbar2Tk)
from matplotlib.figure import Figure
class DraggableLine:
def __init__(self, ax, canvas, XorY):
self.ax = ax
self.c = canvas
self.XorY = XorY
x = [XorY, XorY]
y = [-2, 2]
self.line = lines.Line2D(x, y, color='red', picker=5)
self.ax.add_line(self.line)
self.c.draw_idle()
self.sid = self.c.mpl_connect('pick_event', self.clickonline)
def clickonline(self, event):
if event.artist == self.line:
self.follower = self.c.mpl_connect("motion_notify_event", self.followmouse)
self.releaser = self.c.mpl_connect("button_press_event", self.releaseonclick)
def followmouse(self, event):
self.line.set_xdata([event.xdata, event.xdata])
self.c.draw_idle()
def releaseonclick(self, event):
self.XorY = self.line.get_xdata()[0]
self.c.mpl_disconnect(self.releaser)
self.c.mpl_disconnect(self.follower)
class Example(tk.Frame):
"""Illustrate how to drag items on a Tkinter canvas"""
def __init__(self, parent):
tk.Frame.__init__(self, parent)
fig = Figure(figsize=(5, 4), dpi=100)
t = np.arange(0, 3, .01)
ax = fig.add_subplot(111)
ax.plot(t, 2 * np.sin(2 * np.pi * t))
# create the canvas
canvas = FigureCanvasTkAgg(fig, master=root) # A tk.DrawingArea.
canvas.draw()
canvas.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, expand=1)
self.line = DraggableLine(ax, canvas, 0.1)
if __name__ == "__main__":
root = tk.Tk()
Example(root).pack(fill="both", expand=True)
root.mainloop()
I'm not sure how to do it with tkinter or pyQt but I know how to make something like this with PyGame which is another GUI solution for python. I hope this example helps you:
import pygame
SCREEN_WIDTH = 430
SCREEN_HEIGHT = 410
WHITE = (255, 255, 255)
RED = (255, 0, 0)
FPS = 30
pygame.init()
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
rectangle = pygame.rect.Rect(176, 134, 17, 170)
rectangle_draging = False
clock = pygame.time.Clock()
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 1:
if rectangle.collidepoint(event.pos):
rectangle_draging = True
mouse_x, mouse_y = event.pos
offset_x = rectangle.x - mouse_x
offset_y = rectangle.y - mouse_y
elif event.type == pygame.MOUSEBUTTONUP:
if event.button == 1:
rectangle_draging = False
print("Line is at: (", rectangle.x, ";", rectangle.y,")")
elif event.type == pygame.MOUSEMOTION:
if rectangle_draging:
mouse_x, mouse_y = event.pos
rectangle.x = mouse_x + offset_x
rectangle.y = mouse_y + offset_y
screen.fill(WHITE)
pygame.draw.rect(screen, RED, rectangle)
pygame.display.flip()
clock.tick(FPS)
pygame.quit()
And when you move the line around, the console prints the location that it is in.
from tkinter import *
WIDTH = 800
HEIGHT = 950
RAD = 20
SPEED = 30
class mainHero():
def __init__(self):
self.image = PhotoImage(file="darth_vader.png")
self.imageSize = [112,180]
self.right_side = WIDTH/2+self.imageSize[0]/2
self.left_side = WIDTH/2-self.imageSize[0]/2
self.obj = canv.create_image((WIDTH/2,HEIGHT-self.imageSize[0]/2), image = self.image)
def move(self, event):
if event.keysym == "Right":
if self.right_side+SPEED<WIDTH:
canv.move(self.obj, SPEED, 0)
self.right_side += SPEED
self.left_side += SPEED
if event.keysym == "Left":
if self.left_side-SPEED>0:
canv.move(self.obj, -SPEED, 0)
self.right_side -= SPEED
self.left_side -= SPEED
print(self.left_side, self.right_side)
root = Tk()
root.title("YeGame")
root.minsize(width = WIDTH, height = HEIGHT)
root.maxsize(width = WIDTH, height = HEIGHT)
canv = Canvas(root,width =WIDTH,height = HEIGHT, bg="green")
canv.create_rectangle(0, 0, WIDTH%SPEED-1, HEIGHT, fill = "yellow")
canv.create_rectangle(WIDTH-WIDTH%SPEED+1, 0, WIDTH, HEIGHT, fill = "yellow")
m = canv.create_image((100,100), image = PhotoImage(file="smallnight.gif"))
canv.pack()
canv.focus_set()
me = mainHero()
canv.bind("<KeyPress>", me.move)
root.mainloop()
This code should create game. But I don't understand why I can see Darth Vader on Canvas but can't see background of Canvas. It should be image of Space. Code which add Darth Vader works, but code which add background doesn't work. Show me please how I can do it in right way.
Photo
The image should be declared before calling create_image like you did above for mister Vader:
root = Tk()
root.title("YeGame")
root.minsize(width = WIDTH, height = HEIGHT)
root.maxsize(width = WIDTH, height = HEIGHT)
canv = Canvas(root,width =WIDTH,height = HEIGHT, bg="green")
canv.create_rectangle(0, 0, WIDTH%SPEED-1, HEIGHT, fill = "yellow")
canv.create_rectangle(WIDTH-WIDTH%SPEED+1, 0, WIDTH, HEIGHT, fill = "yellow")
background = PhotoImage(file="smallnight.gif")
m = canv.create_image((100,100), image = background)
canv.pack()
canv.focus_set()
me = mainHero()
canv.bind("<KeyPress>", me.move)
root.mainloop()