Tkinter when a button is clicked? - python

So im making a game in Tkinter but what I want to do is when I click a button on my keyboard for example "w" it runs a function that increments x by 5 for example.
Heres my code.
__author__ = 'Zac'
from Tkinter import *
from random import randint
class Application:
def circle(self, r, x, y):
return (x-r, y-r, x+r, y+r)
def square(self, s, x, y):
return (x, y, s, s)
def __init__(self, canvas, r, x, y):
self.canvas = canvas
self.r = r
self.x = x
self.y = y
self.ball = canvas.create_oval(self.circle(r, x, y))
root = Tk()
canvas = Canvas(root, width = 1000, height = 1000)
canvas.pack()
ball1 = Application(canvas, 20, 50, 50)
root.mainloop()

Use widget.bind method to bind keypress with event handler.
For example:
....
ball1 = Application(canvas, 20, 50, 50)
def increase_circle(event):
canvas.delete(ball1.ball)
ball1.r += 5
ball1.ball = canvas.create_oval(ball1.circle(ball1.r, ball1.x, ball1.y))
root.bind('<w>', increase_circle) # <--- Bind w-key-press with increase_circle
root.mainloop()
See Events and Bindings.

Related

Tkinter smooth transition between frames

# Import the required libraries
from tkinter import *
from PIL import Image, ImageTk
# Create an instance of tkinter frame
win = Tk()
# Set the size of the tkinter window
win.geometry("700x350")
# Define a Canvas widget
canvas = Canvas(win, width=600, height=400, bg="white")
canvas.pack(pady=20)
# Add Images to Canvas widget
x = 250
y = 120
image = ImageTk.PhotoImage(Image.open('map.png'))
img = canvas.create_image(x, y, anchor=NW, image=image)
def left(e):
global x, y
x -= 0.9
canvas.coords(img, x, y)
def right(e):
global x, y
x += 0.9
canvas.coords(img, x, y)
def up(e):
global x, y
y -= 0.9
canvas.coords(img, x, y)
def down(e):
global x, y
y += 0.9
canvas.coords(img, x, y)
# Bind the move function
win.bind("<Left>", left)
win.bind("<Right>", right)
win.bind("<Up>", up)
win.bind("<Down>", down)
win.mainloop()
map.png is https://www.dropbox.com/s/wfq4skai66nexxr/map.png?dl=0. If you press left or right arrow keys, you will see the black words look slightly lagging. Is there a way to fix that without changing the 0.9?

How to move a shape while retaining original size in tkinter

I am trying to have the rectangle I create spawn at the bottom of my tkinter canvas instead of spawning at the top without affecting its size. I have only found this post and this doesn't help me as it does not describe how to move the shape to the bottom of the canvas
Here's my code:
from tkinter import *
from tkinter.ttk import *
#Temporary
width = 1024
height=768
class GFG:
def __init__(self, master = None):
self.master = master
self.master.configure(bg="black") #Apart from the canvas colour
self.x = 0
self.y = 0
self.canvas = Canvas(master, background="black", highlightthickness=0, width=width, height=height) #Canvas colour
self.rectangle = self.canvas.create_rectangle(5, 5, 25, 25, fill='white')
self.canvas.pack()
self.movement()
def movement(self):
self.canvas.move(self.rectangle, self.x, self.y)
self.canvas.after(100, self.movement)
def left(self, event):
print(event.keysym)
self.x = -5
self.y = 0
def right(self, event):
print(event.keysym)
self.x = 5
self.y = 0
if __name__ == "__main__":
master = Tk()
master.title("Black Hole Settlers")
gfg = GFG(master)
master.bind("<KeyPress-Left>", lambda e: gfg.left(e))
master.bind("<KeyPress-Right>", lambda e: gfg.right(e))
mainloop()
Pastebin
Thanks,
swanserquack

Manual Annotation with Tkinter

I am using Tkinter to import images with Openslide. I would like to integrate a manual annotation module into my program like this:
class ResizableCanvas(Canvas):
def __init__(self, parent, **kwargs):
Canvas.__init__(self, parent, **kwargs)
self.bind("<Configure>", self.on_resize)
self.height = self.winfo_reqheight()
self.width = self.winfo_reqwidth()
def on_resize(self, event):
wscale = float(event.width) / self.width
hscale = float(event.height) / self.height
self.width = event.width
self.height = event.height
self.config(width=self.width, height=self.height)
class ViewerTab:
def __init__(self, master, model, dim=800):
self.sideFrame = ttk.Frame(self.master, width=100)
self.coords = {"x":0,"y":0,"x2":0,"y2":0}
self.lines = []
def click(self):
self.coords["x"] = self.x
self.coords["y"] = self.y
self.lines.append(self.canvas.create_line(self.coords["x"],self.coords["y"],self.coords["x"],self.coords["y"]))
def drag(self):
# update the coordinates from the event
self.coords["x2"] = self.x
self.coords["y2"] = self.y
self.canvas.coords(self.lines[-1], self.coords["x"],self.coords["y"],self.coords["x2"],self.coords["y2"])
#self.canvas.bind("<Button-1>", self.dirbutton)
#self.canvas.bind("<B1-Motion>", self.move)
self.canvas.bind("<ButtonRelease-1>", self.nomove)
self.canvas.bind("<Button-2>", self.get_position)
self.canvas.bind("<ButtonPress-1>", self.click)
self.canvas.bind("<B1-Motion>", self.drag)
So if I got it right from the comments, the issue is to be able to both pan the slide and draw on it using binding to mouse clicks and motion. There are several way to do that, for instance:
Use radiobuttons so that the user selects the "mode": either pan or annotate. Here is a small example based on https://stackoverflow.com/a/50129744/6415268 for the drawing part. The click() and drag() functions do different actions depending on the selected mode (stored a the StringVar).
import tkinter as tk
coords = {"x": 0, "y": 0, "x2": 0, "y2": 0}
# keep a reference to all lines by keeping them in a list
lines = []
def click(event):
if mode.get() == "pan":
canvas.scan_mark(event.x, event.y)
else:
# define start point for line
coords["x"] = canvas.canvasx(event.x)
coords["y"] = canvas.canvasy(event.y)
# create a line on this point and store it in the list
lines.append(canvas.create_line(coords["x"], coords["y"], coords["x"], coords["y"]))
def drag(event):
if mode.get() == "pan":
canvas.scan_dragto(event.x, event.y, gain=1)
else:
# update the coordinates from the event
coords["x2"] = canvas.canvasx(event.x)
coords["y2"] = canvas.canvasy(event.y)
# Change the coordinates of the last created line to the new coordinates
canvas.coords(lines[-1], coords["x"], coords["y"], coords["x2"], coords["y2"])
root = tk.Tk()
mode = tk.StringVar(root, "pan")
toolbar = tk.Frame(root)
toolbar.pack(fill='x')
tk.Radiobutton(toolbar, text="Pan",
variable=mode, value="pan").pack(side='left')
tk.Radiobutton(toolbar, text="Annotate",
variable=mode, value="annotate").pack(side='left')
canvas = tk.Canvas(root, bg="white")
canvas.create_rectangle(0, 0, 50, 50, fill='red')
canvas.create_rectangle(400, 400, 450, 450, fill='blue')
canvas.pack(fill='both')
canvas.bind("<ButtonPress-1>", click)
canvas.bind("<B1-Motion>", drag)
root.mainloop()
Another possibility is to use different bindings for the two kinds of actions using event modifiers (e.g. pressing the Ctrl, Shift or Alt key). For instance, the panning can be bound to Ctrl + mouse events while the drawing happens on simple mouse clicks and motion.
import tkinter as tk
coords = {"x": 0, "y": 0, "x2": 0, "y2": 0}
# keep a reference to all lines by keeping them in a list
lines = []
def draw_click(event):
# define start point for line
coords["x"] = canvas.canvasx(event.x)
coords["y"] = canvas.canvasy(event.y)
# create a line on this point and store it in the list
lines.append(canvas.create_line(coords["x"], coords["y"], coords["x"], coords["y"]))
def draw_drag(event):
# update the coordinates from the event
coords["x2"] = canvas.canvasx(event.x)
coords["y2"] = canvas.canvasy(event.y)
# Change the coordinates of the last created line to the new coordinates
canvas.coords(lines[-1], coords["x"], coords["y"], coords["x2"], coords["y2"])
root = tk.Tk()
toolbar = tk.Frame(root)
toolbar.pack(fill='x')
canvas = tk.Canvas(root, bg="white")
canvas.create_rectangle(0, 0, 50, 50, fill='red')
canvas.create_rectangle(400, 400, 450, 450, fill='blue')
canvas.pack(fill='both')
canvas.bind("<ButtonPress-1>", draw_click)
canvas.bind("<B1-Motion>", draw_drag)
canvas.bind('<Control-ButtonPress-1>', lambda event: canvas.scan_mark(event.x, event.y))
canvas.bind("<Control-B1-Motion>", lambda event: canvas.scan_dragto(event.x, event.y, gain=1))
root.mainloop()

Why doesn't this image move when the key is pressed?

Python and Tkinter nebwie. I tried making an image in tkinter and have it move using the arrows. The image shows just it should, but when I try to move it using the arrows, it doesn't work at all. Any idea why? I use python 2.7.18 and I'm on the latest version of Ubuntu
from Tkinter import *
############
#things
w = 500
h = 500
width=w
height=h
#############
######################################################################
#window
window = Tk()
window.title("Moving image")
canvas = Canvas(window, width = 500, height = 500)
canvas.pack()
my_image = PhotoImage(file="/home/user/Documents/ddd.png")
canvas.create_image(260, 125, anchor = NW, image=my_image)
#######################################################################
################################
#var
def up(event):
x = 0
y = -10
canvas.move(my_image, x, y)
def down(event):
x = 0
y = 10
canvas.move(my_image, x, y)
def left(event):
x = -10
y = 0
canvas.move(my_image, x, y)
def right(event):
x = 10
y = 0
canvas.move(my_image, x, y)
###############################
###############################
#binds
window.bind("<Up>", up)
window.bind("<Down>", down)
window.bind("<Left>", left)
window.bind("<Right>", right)
window.mainloop()
##############################
You are trying to move the wrong object. Use the object, which is returned by canvas.create_image:
image_id = canvas.create_image(260, 125, anchor = NW, image=my_image)
...
canvas.move(image_id, x, y)
Alternatively, you can attach a tag to the image:
canvas.create_image(260, 125, anchor=NW, image=my_image, tag="move")
...
canvas.move("move", x, y)
This will move all objects, which have this specific tag attached.

Is there a way to have a draggable ruler in tkinter?

Is it possible?
Just to place it anywhere onto the window and drag it anywhere I want it.
Here is an example of draggable item I am looking to achieve like from HTML (I know, it's got nothing to do with html): How TO - Create a Draggable HTML Element.
Here is an example of what I mean by a ruler. A ruler like this:
It's only for display purposes and not calculating anything..
I'll be using Grid manager in this case.
I'll be happy to see any examples!
Standard module tkinter and ttk doesn't have rulers and I don't know any external module for tkinter which has rulers.
Using Canvas I can create widget which draws lines with numbers.
But it is still primitive widget which doesn't resize, doesn't scroll lines and numbers, doesn't rescale, and doesn't show mouse position.
EDIT: Now rules show mouse position using red lines. But if there is no Canvas then they have to know offset - how far they are from left top corner of window.
import tkinter as tk
class VRuler(tk.Canvas):
'''Vertical Ruler'''
def __init__(self, master, width, height, offset=0):
super().__init__(master, width=width, height=height)
self.offset = offset
step = 10
# start at `step` to skip line for `0`
for y in range(step, height, step):
if y % 50 == 0:
# draw longer line with text
self.create_line(0, y, 13, y, width=2)
self.create_text(20, y, text=str(y), angle=90)
else:
self.create_line(2, y, 7, y)
self.position = self.create_line(0, 0, 50, 0, fill='red', width=2)
def set_mouse_position(self, y):
y -= self.offset
self.coords(self.position, 0, y, 50, y)
class HRuler(tk.Canvas):
'''Horizontal Ruler'''
def __init__(self, master, width, height, offset=0):
super().__init__(master, width=width, height=height)
self.offset = offset
step = 10
# start at `step` to skip line for `0`
for x in range(step, width, step):
if x % 50 == 0:
# draw longer line with text
self.create_line(x, 0, x, 13, width=2)
self.create_text(x, 20, text=str(x))
else:
self.create_line((x, 2), (x, 7))
self.position = self.create_line(0, 0, 0, 50, fill='red', width=2)
def set_mouse_position(self, x):
x -= self.offset
self.coords(self.position, x, 0, x, 50)
def motion(event):
x, y = event.x, event.y
hr.set_mouse_position(x)
vr.set_mouse_position(y)
def click(event):
print(event.x, event.y)
root = tk.Tk()
root['bg'] = 'black'
vr = VRuler(root, 25, 250)#, offset=25)
vr.place(x=0, y=28)
hr = HRuler(root, 250, 25)#, offset=25)
hr.place(x=28, y=0)
c = tk.Canvas(root, width=250, height=250)
c.place(x=28, y=28)
#root.bind('<Motion>', motion) # it needs offset=28 if there is no Canvas
#root.bind('<Button-1>', click)
c.bind('<Motion>', motion)
c.bind('<Button-1>', click)
root.mainloop()

Categories

Resources