How do I capture keystrokes directly on the tkinter canvas? - python-3.x

I'm having trouble capturing keystrokes from the tkinter canvas. The keystroke is captured properly if I bind it to a label widget but not to the canvas. My code is here:
from tkinter import *
root = Tk()
class keyPresser():
# For test purposes, move the rectangle and print a message.
# Nothing is happening
def handle_down_key(self,event):
self.canvas.focus_set()
self.canvas.move(self.rectangle,10,10)
print('Down arrow key pressed')
def __init__(self):
self.canvas = Canvas(root, width=400, height=400)
self.rectangle = self.canvas.create_rectangle(
0, 0, 20, 20, fill = "black")
self.canvas.bind("<Down>", self.handle_down_key)
self.canvas.focus()
self.canvas.pack()
mm = keyPresser()
root.mainloop()
Thanks for any suggestions.

Here you go !
from tkinter import *
root = Tk()
class keyPresser():
# For test purposes, move the rectangle and print a message.
# Nothing is happening
def handle_down_key(self, event):
self.canvas.focus_set()
self.canvas.move(self.rectangle, 10, 10)
print('Down arrow key pressed')
def __init__(self):
self.canvas = Canvas(root, width=400, height=400)
self.rectangle = self.canvas.create_rectangle(
0, 0, 20, 20, fill="black")
root.bind("<Down>", self.handle_down_key)
self.canvas.focus()
self.canvas.pack()
mm = keyPresser()
root.mainloop()

Related

How to make a button change colors by binding in a class

I tried to use bind to bind the mouse clicks to change colors based on the foreground and background of the buttons
from tkinter import *
class Clicks():
def __init__(self, master):
frame=Frame(master)
frame.pack()
#trying to bind the mouse clicks to change the color of the button
self.button1= Button(frame, text="Click Me!", fg='red', bg='black')
self.button1.bind("<Button-1>", fg='black')
self.button1.bind("<Button-3>", bg='red')
self.button1.grid(row = 0, column = 1, sticky = W)
root = Tk()
b = Clicks(root)
root.mainloop()
TypeError: bind() got an unexpected keyword argument 'fg'
Please check the snippet. You can use 2 approaches here.
First you can bind using lambda function
from tkinter import *
class Clicks():
def __init__(self, master):
frame=Frame(master)
frame.pack()
self.button1= Button(frame, text="Click Me!", fg='red', bg='black')
self.button1.bind("<Button-1>", lambda event, b=self.button1: b.configure(bg="green",fg="blue"))
self.button1.grid(row = 0, column = 1, sticky = W)
root = Tk()
b = Clicks(root)
root.mainloop()
Second you can do via passing command to access function
from tkinter import *
class Clicks():
def __init__(self, master):
frame=Frame(master)
frame.pack()
self.button1= Button(frame, text="Click Me!",command=self.color, fg='red', bg='black')
self.button1.grid(row = 0, column = 1, sticky = W)
def color(self):
self.button1.configure(bg = "green",fg="blue")
root = Tk()
b = Clicks(root)
root.mainloop()

Cropping multiple parts of the image and placing on the canvas in Tkinter

I am new to the Tkinter platform so please help me where I'm going wrong.
I have a floorplan image in which I want to cut the objects in it and place it on a canvas screen so that individual objects can be dragged if I want.
I'm able to cut and paste the objects on the screen except the first object. It is not placed on the screen. Can anyone help me?
I am using a Matlab code to identify the objects in the floorplan image. I am attaching the Matlab file.
Is it possible to add the wall to the screen? I have no idea at all. Can anyone suggest how to add the wall?
Here is my code
import tkinter as tk
from tkinter import *
from PIL import Image,ImageTk
from scipy.io import loadmat
root = tk.Tk()
canvas = tk.Canvas(width=800, height=800)
canvas.grid(row=4,column=0,sticky=(N,W,E,S))
#canvas.config(width=100,height=100)
root.grid_columnconfigure(0, weight=1)
root.grid_rowconfigure(4, weight=1)
mfile=loadmat('C:\\Users\\User\\Desktop\\tkinter_codes\\obj identification\\ans.mat')
#print(mfile.values())
#print(len(mfile['ans'][0]))
print(mfile.values())
class Example(tk.Frame):
def __init__(self, parent):
self.parent =parent
tk.Frame.__init__(self, parent)
self.canvas = tk.Canvas(width=800, height=800)
self.canvas.grid(row=0,column=0,sticky=(N,W,E,S))
#canvas.pack (expand =1, fill =tk.BOTH)
self.canvas.tag_bind("DnD","<Button-1>")
self._drag_data = {"x": 0, "y": 0, "item": None}
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)
self.canvas.bind("<ButtonPress-1>", self.on_button_1)
self.iimg=Image.open("C:\\Users\\User\\Desktop\\tkinter_codes\\floorplans\\ROBIN\\Dataset_3rooms\\Cat1_1.jpg")
#iimg=iimg.resize((1000, 800), Image.ANTIALIAS)
self.canvas.img=ImageTk.PhotoImage(self.iimg)
#canvas.img = canvas.img.resize((250, 250), Image.ANTIALIAS)
self.canvas_img=canvas.create_image(0,0,image=self.canvas.img,anchor="nw")
self.mylist=[]
for x in range(len(mfile['ans'][0])):
#canvas.create_rectangle((mfile['ans'][0][x][0][0],mfile['ans'][0][x][0][1],mfile['ans'][0][x][0][0]+mfile['ans'][0][x][0][2],mfile['ans'][0][x][0][1]+mfile['ans'][0][x][0][3]),outline='red',tags=("token","DnD"))
self.im_crop = self.iimg.crop((mfile['ans'][0][x][0][0],mfile['ans'][0][x][0][1],mfile['ans'][0][x][0][0]+mfile['ans'][0][x][0][2],mfile['ans'][0][x][0][1]+mfile['ans'][0][x][0][3]))
self.canvas.im_crop2=ImageTk.PhotoImage(self.im_crop)
self.canvas.create_image(mfile['ans'][0][x][0][0],mfile['ans'][0][x][0][1], image=self.canvas.im_crop2)
#canvas.create_image(1000,1000,image=im_crop2)
#if(x>=0):
self.mylist.append(self.canvas.im_crop2)
#im_crop.show()
#canvas.iiiimg=ImageTk.PhotoImage(im_crop)
#canvas.create_image(150,150,image=canvas.im_crop2)
self.popup = tk.Menu(root, tearoff=0)
#self.popup.add_command(label="delete",command=lambda: self.dele(id))
self.popup.add_command(label="delete",
command=lambda: self.dele(id))
self.popup.add_command(label="add",command= lambda: root.bind("<Button-1>",self.addn))
root.bind("<Button-3>", self.do_popup)
self.canvas.delete(self.canvas_img)
def do_popup(self,event):
# display the popup menu
try:
self.popup.tk_popup(event.x_root, event.y_root, 0)
finally:
# make sure to release the grab (Tk 8.0a1 only)
self.popup.grab_release()
def on_button_1(self, event):
iid = self.canvas.find_enclosed(event.x-150, event.y-150, event.x + 150, event.y + 100)
#iid=canvas.find_closest(event.x, event.y)[0]
self.canvas.itemconfigure("DEL")
self.canvas.dtag("all","DEL")
self.canvas.itemconfigure(iid, tags=("DEL","DnD","token","drag"))
#canvas.unbind("<Button-1>")
def create_token(self, x, y, color):
"""Create a token at the given coordinate in the given color"""
self.canvas.create_rectangle(
x ,
y ,
x + 50,
y + 50,
outline=color,
fill=color,
tags=("token","DnD"),
)
def create_token1(self,x,y,color):
self.canvas.create_rectangle(
x ,
y ,
x + 25,
y + 25,
outline=color,
fill=color,
tags=("token","DnD"),
)
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]
rect=self.canvas.bbox(self._drag_data["item"])
self.canvas.addtag_enclosed("drag",*rect)
print(rect)
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
self.canvas.dtag("drag","drag")
def drag(self, event):
"""Handle dragging of an object"""
# compute how much the mouse has moved
self.delta_x = event.x - self._drag_data["x"]
self.delta_y = event.y - self._drag_data["y"]
# move the object the appropriate amount
self.canvas.move("drag", self.delta_x, self.delta_y)
# record the new position
self._drag_data["x"] = event.x
self._drag_data["y"] = event.y
def dele(self,id):
#canvas.tag_bind(id,"<Button-1>")
self.canvas.delete("DEL")
def addn(self,event):
canvas.create_rectangle(event.x,event.y,event.x+25,event.y+25,fill='red',tags=("DnD","token"))
root.unbind("<Button-1>")
Example(root) #pack(fill="both", expand=True)
root.mainloop()
This is the Matlab code I am using for identifying objects

How stop sketch in tkinter canvas

I have few line of code here which draw circle in tkinter canvas but want i want to do is to stop the sketch to the point where it started so i use sleep but i stop the sketch where it has gotten to then it continue.
So i wrote this function
def stop_extent():
canvas.create_arc(0, 0, 0, 0, extent=0, outline="red", tags=("arc",))
extent = float(canvas.itemcget("arc", "extent"))
extent = extent + 5.0
canvas.itemconfigure("arc", extent=extent)
canvas.after(100, stop_extent)
and set all the values to 0 but still it doesn't stopped it and the label doesn't configure too.
import tkinter as tk
import time
def change_extent():
l.config(text="sketch in progress...")
canvas.create_arc(350, 100, 220, 220, extent=0, outline="yellow", tags=("arc",))
extent = float(canvas.itemcget("arc", "extent"))
extent = extent + 5.0
canvas.itemconfigure("arc", extent=extent)
canvas.after(100, change_extent)
def stop_extent():
l.config(text="sketch stopped...")
time.sleep(10)
l.config(text="sketch stopped...")
root = tk.Tk()
root.geometry("600x400")
canvas = tk.Canvas(root, width=200, height=200, background="dodger blue")
canvas.pack(fill="both", expand=True)
l = tk.Label(canvas, bg="dodger blue", fg="white")
l.place(x=250, y=20)
b= tk.Button(canvas, text="Start sketch", command=change_extent, width=25, fg='dodger blue')
b.place(x=220, y=330)
b= tk.Button(canvas, text="stop sketch", command=stop_extent, width=25, fg='dodger blue')
b.place(x=220, y=370)
root.mainloop()
You can keep track of the call back generated by canvas.after in the change_extent method, and cancel it with canvas.after_cancel in the stop_extent method; in the following example, I use a global variable stop to demonstrate it.
Using time.sleep in a GUI application is generally a bad idea.
You also do not need to recreate the arc each time you want to modify its extent, but that is outside the scope of your question.
import tkinter as tk
import time
def change_extent():
global stop
l.config(text="sketch in progress...")
extent = float(canvas.itemcget(arc_item, "extent"))
canvas.itemconfigure("arc", extent=extent+5)
stop = canvas.after(100, change_extent)
def stop_extent():
l.config(text="sketch stopped...")
print(stop)
canvas.after_cancel(stop)
canvas.itemconfigure("arc", extent=0) # <- reset to straight line start
stop = None
root = tk.Tk()
root.geometry("600x400")
canvas = tk.Canvas(root, width=200, height=200, background="dodger blue")
canvas.pack(fill="both", expand=True)
arc_item = canvas.create_arc(350, 100, 220, 220, extent=0, outline="yellow", tags=("arc",))
l = tk.Label(canvas, bg="dodger blue", fg="white")
l.place(x=250, y=20)
b= tk.Button(canvas, text="Start sketch", command=change_extent, width=25, fg='dodger blue')
b.place(x=220, y=330)
b= tk.Button(canvas, text="stop sketch", command=stop_extent, width=25, fg='dodger blue')
b.place(x=220, y=370)
root.mainloop()

tkinter Canvas window size

I need to know when the Canvas is resized (eg when the master frame gets maximized) the new Canvas window size.
Unfortunately, if I try self.canvas['width'] it always seems to me I get back the width it had whenever I initialized it and not the current width.
How do I get the current Canvas window dimensions?
When you retrieve self.canvas['width'], you are asking tkinter to give you the configured width of the widget, not the actual width. For the actual width you can use .winfo_width().
If you want to know when the canvas is resized, you can add a binding to the <Configure> event on the widget. The event object that is passed to the binding has a width attribute which also has the actual width of the widget.
Here's an example:
import tkinter as tk
root = tk.Tk()
canvas = tk.Canvas(root, width=200, height=200, background="bisque")
canvas.pack(side="bottom", fill="both", expand=True)
canvas.create_text(10, 30, anchor="sw", tags=["event"])
canvas.create_text(10, 30, anchor="nw", tags=["cget"])
def show_width(event):
canvas.itemconfigure("event", text="event.width: %s" % event.width)
canvas.itemconfigure("cget", text="winfo_width: %s" % event.widget.winfo_width())
canvas.bind("<Configure>", show_width)
root.mainloop()
one possible solution:
try:
import Tkinter as tk
except:
import tkinter as tk
class myCanvas(tk.Frame):
def __init__(self, root):
#self.root = root
self.w = 600
self.h = 400
self.canvas = tk.Canvas(root, width=self.w, height=self.h)
self.canvas.pack( fill=tk.BOTH, expand=tk.YES)
root.bind('<Configure>', self.resize)
def resize(self, event):
self.w = event.width
self.h = event.height
print ('width = {}, height = {}'.format(self.w, self.h))
root = tk.Tk()
root.title('myCanvas')
myCanvas(root)
root.mainloop()
Notice that the size informed by the event is 2 pixels wider in either direction. That's the border, I suppose.

Changing rectangle color on click in Python using Tk

I'm trying to get a Tk rectangle created on a canvas to change its color when clicked. Right now, no color change happens when the rectangle is clicked. What do I need to be doing differently?
This is in Python3.5, by the way.
from tkinter import *
def set_color(id):
global alive, colors
alive = not alive
col = colors[alive]
canvas.itemconfigure(id, fill=col)
root = Tk()
canvas = Canvas(root)
canvas.grid(column=1, row=1, sticky=(N, S, E, W))
alive = False
colors = {True: "green", False: "red"}
id = canvas.create_rectangle((1, 1, 60, 60), fill="red")
canvas.tag_bind(id, "<ButtonPress-1>", set_color)
root.mainloop()
Wrap it in a class and create as many instances as you want. http://www.freenetpages.co.uk/hp/alan.gauld/tutclass.htm
class OneSquare():
def __init__(self, can, start_x, start_y, size):
self.can=can
self.id = self.can.create_rectangle((start_x, start_y,
start_x+size, start_y+size), fill="red")
self.can.tag_bind(self.id, "<ButtonPress-1>", self.set_color)
self.color_change=True
def set_color(self, event=None):
self.color_change = not self.color_change
color="red"
if not self.color_change:
color="green"
self.can.itemconfigure(self.id, fill=color)
root = Tk()
canvas = Canvas(root)
canvas.grid(column=1, row=1, sticky=(N, S, E, W))
OS1=OneSquare(canvas, 1, 1, 60)
OS2=OneSquare(canvas, 90, 1, 30)
OS3=OneSquare(canvas, 1, 90, 90)
Button(root, text="Exit", bg="orange",
command=root.quit).grid(row=2)
root.mainloop()
tag_bind sends an event to the function, so "id" is overwritten and now contains the event. So you can change from
def set_color(id):
## to
def set_color(event=None):
and it will work because there is only one object/id to deal with in this program. event=None is used because it assigns a default value when no event is sent to the function, as in a button press for example, so will work for all responses.

Resources