How to bind spacebar key to a certain method in tkinter (python) - python

I am working on a project in python, and I made a method to draw a specific thing in tkinter. I want it so that whenever I press the spacebar, the image will redraw itself (run the method again because I coded the method so that it could redraw over itself). How exactly would I bind the spacebar to the method so that the program would run, draw, and re-draw if I pressed the spacebar?
for example, i want it so that whenever I press space, the program draws in a random location on the canvas:
from Tkinter import *
from random import *
root=Tk()
canvas=Canvas(root,width=400,height=300,bg='white')
def draw():
canvas.delete(ALL)# clear canvas first
canvas.create_oval(randint(0,399),randint(0,299),15,15,fill='red')
draw()
canvas.pack()
root.mainloop()
how would i bind the spacebar to the method?

from Tkinter import *
from random import *
root=Tk()
canvas=Canvas(root,width=400,height=300,bg='white')
def draw(event=None):
canvas.delete(ALL)# clear canvas first
canvas.create_oval(randint(0,399),randint(0,299),15,15,fill='red')
draw()
canvas.pack()
root.bind("<space>", draw)
root.mainloop()

You could do something like this:
from Tkinter import *
from random import *
root=Tk()
canvas=Canvas(root,width=400,height=300,bg='white')
def draw(event):
if event.char == ' ':
canvas.delete(ALL)# clear canvas first
canvas.create_oval(randint(0,399),randint(0,299),15,15,fill='red')
root.bind('<Key>', draw)
canvas.pack()
root.mainloop()
Basically, you bind your drawing function to some top-level element to the <Key> binding which is triggered whenever a key on the keyboard is pressed. Then, the event object that's passed in has a char member which contains a string representing the key that was pressed on the keyboard.
The event will only be triggered when the object it's bound to has focus, which is why I'm binding the draw method to the root object, since that'll always be in focus.

You can aslo use canvas.bind_all("<space>", yourFunction)
That will listen for events in the whole application and not only on widget.

Related

How to detect which key was pressed on keyboard/mouse using tkinter/python?

I'm using tkinter to make a python app and I need to let the user choose which key they will use to do some specific action. Then I want to make a button which when the user clicks it, the next key they press as well in keyboard as in mouse will be detected and then it will be bound it to that specific action. How can I get the key pressed by the user?
To expand on #darthmorf's answer in order to also detect mouse button events, you'll need to add a separate event binding for mouse buttons with either the '<Button>' event which will fire on any mouse button press, or '<Button-1>', (or 2 or 3) which will fire when that specific button is pressed (where '1' is the left mouse button, '2' is the right, and '3' is the middle...though I think on Mac the right and middle buttons are swapped).
import tkinter as tk
root = tk.Tk()
def on_event(event):
text = event.char if event.num == '??' else event.num
label = tk.Label(root, text=text)
label.place(x=50, y=50)
root.bind('<Key>', on_event)
root.bind('<Button>', on_event)
root.mainloop()
You can get key presses pretty easily. Without knowing your code, it's hard to say exactly what you will need, but the below code will display a label with the last key pressed when ran and should provide enough of an example to show you how to adapt it to your program!
from tkinter import Tk, Label
root=Tk()
def key_pressed(event):
w=Label(root,text="Key Pressed: "+event.char)
w.place(x=70,y=90)
root.bind("<Key>",key_pressed)
root.mainloop()

How can we bind certain pixels of tkinter window or frame?

Is there anyway to bind certain coordinates of window or frame like when mouse enter these coordinates call this function etc. The reason is that i want to bind these coordinates for scrollbar, So I can hide scrollbar if user leaves that position.
You can use bind and <Enter>
Example:
from tkinter import Button, Tk
root = Tk()
def hover(event):
b.config(bg="blue")
def leave(event):
b.config(bg="white")
b = Button(root, text="Click me!")
b.pack(pady=20)
b.bind("<Enter>", hover)
b.bind("<Leave>", leave)
root.mainloop()
For more bindings, you can refer this:
https://www.geeksforgeeks.org/python-binding-function-in-tkinter/
No, you cannot bind to specific pixels. However, you can simulate that by binding to all mouse movement (eg: <Motion>). In the bound function, you can then determine if the mouse is over whatever region you want to have active.

Is there a way to make a custom askopenfilenames dialog window or at least edit its title bar, close button, etc in tkinter?

I'm making an app in tkinter which uses the ttk.Scale widget to show the process of an mp3 song.
I have a function that I want to add buttons with the names of which (the buttons) should be relied on filenames. Therefore I've made this example:
from tkinter import Tk, Button
from tkinter.filedialog import askopenfilenames
from tkinter.ttk import Scale
from threading import Timer
root = Tk()
slider = Scale(root, from_=0, to=100, orient='horizontal')
slider.pack()
# slider is continuously set to a bigger number so that it keeps going
def update_slider(num):
slider.set(num)
num += 1
root.after(50, update_slider, num)
update_slider(num=0)
# this function creates buttons based on the files opened
def add_buttons():
# the 'X' button of this particular window slows down execution of update_slider function
files = askopenfilenames(title='Add Buttons')
for i in list(files):
Button(root, text=i).pack()
button = Button(root, text='Browse', command=lambda: Timer(0.1, add_buttons).start())
button.pack()
root.mainloop()
The problem I'm facing is that when I open the askopenfilenames dialog box or when I press its 'X' button, my slider which is running continuously in the background gets stuck, and as a result doesn't show the process correctly.
Here is a picture where I hold down the 'X' button and the ttk.Scale stops moving:
I've tried using threading to run the add_buttons function but the behavior of the program remains the same.
Can I edit the askopenfilenames dialog box with something similar like overrideredirect(True) so that I can make my own title bar and 'X' button and the events generated not to slow down my Scale?
Replying to:
I cannot reproduce the issue in Linux, the scale keeps moving no matter what I do with the filedialog window. So this may be an OS specific issue.
I'm aware that this problem doesn't appear on Linux. I faced the same problem with the root's close button and other Toplevels' close button, but I fixed it by replacing the title bar using overrideredirect(True).
Is there anything similar I can do with this askopenfilenames window?

How can I create a button in turtle?

How to create a simple button in turtle, python, where if you click it, you can define it to print messages, or do other, more complex things.
You can embed turtle in tkinter, as #JoshuaNixon suggests in his comment, using tkinter buttons to control your turtle canvas. If you want to work within standalone turtle, I recommend using a turtle as a button as they can be coerced into any shape and/or color and have individual onclick event handlers so you don't have to figure out where the user clicked on the screen:
from turtle import Screen, Turtle
CURSOR_SIZE = 20
FONT_SIZE = 12
FONT = ('Arial', FONT_SIZE, 'bold')
def draw_onclick(x, y):
turtle.dot(100, 'cyan')
button = Turtle()
button.hideturtle()
button.shape('circle')
button.fillcolor('red')
button.penup()
button.goto(150, 150)
button.write("Click me!", align='center', font=FONT)
button.sety(150 + CURSOR_SIZE + FONT_SIZE)
button.onclick(draw_onclick)
button.showturtle()
turtle = Turtle()
turtle.hideturtle()
screen = Screen()
screen.mainloop()
Note that Turtle.onclick() is different than Screen().onclick -- one only happens when clicking on a specific turtle instance whereas the other happens when clicking anywhere on the screen.
Since the Python Turtle Graphics Module is built on top of Tkinter, a Tkinter button should work on a turtle screen
from turtle import Screen
from tkinter import *
screen = Screen()
screen.setup(width=600, height=400)
def do_something():
print("Good bye")
canvas = screen.getcanvas()
button = Button(canvas.master, text="Exit", command=do_something)
button.pack()
button.place(x=300, y=100) # place the button anywhere on the screen
screen.exitonclick()
I haven't tried this out but this might work:
root = turtle.Screen()._root
btn = Button(root, text="This button exists in turtle")
btn.pack()
That should be it!
Note: Since turtle is based on tkinter the turtle.Screen() contains the tk() root
We are able to access that root and create a tkinter button and add it to it.
Edit: If you add a command parameter in pack you can make the button execute a function
To create a simple button, there might be other ways, but this is how I do it.
import turtle
def button(x,y):
if x < 50 and x > -50 and y < 50 and y > -50:
print(f"Your coordinates are: ({x}, {y}).")
turtle.onscreenclick(button, 1, add=False)
turtle.done()
To explain this, button is just a function, it has nothing to do with an actual button yet. The if statement in there basically takes the x,y variables that are its parameters, and checks whether they are between two numbers, in this case, coordinates.
The onscreenclick function takes three parameters. The first is a function with two parameters. Wherever you click on the turtle pop-up, it will take the x,y coordinates of where you clicked and inserts it into the function. The second is a number. This number refers to how you are going to click it (Ex. right-click, left-click, etc.) In most cases, it is 1 since 1 is left-click. Finally, the third parameter is necessary when you have multiple buttons. If you are creating a second, third, etc. button, and you want to create the new button without overwriting the previous button, you write add=True. If you want to make it so all previous buttons are canceled, you write True. So, finally, the code above would print the coordinates of where you clicked if they were both between -50 and 50.
You can do a lot of useful things with this function. You can create it as a temporary button to help you while writing with turtle, where the "whole screen" is a large button where it prints the x,y coordinates of where you clicked. This can be useful in getting the approximate coordinates of where you want your turtle to go next.
Or you could use it your actual code, to get information from the user or as part of a game.
All in all, this is a simple way to create a button just using turtle and no other modules and has great flexibility.
If there are any other ways, using or not using turtle, complex or simple, please post it below as an answer.
NOTE: You wouldn't be able to "see" the button by default. If you wanted, though, you could make a turtle draw the outline of the button or something.

Checkbutton responds to clicks on text

By default, tkinter's Checkbutton widget responds to clicks anywhere in the widget, rather than just in the check box field.
For example, consider the following (Python 2) code:
import Tkinter as tk
main = tk.Tk()
check = tk.Checkbutton(main, text="Click").pack()
main.mainloop()
Running this code results in a small window, with a single check box, accompanied by the word "Click". If you click on the check box, it is toggled.
However, this also happens if you click on the text of the widget, rather than the check box.
Is this preventable? I could make a separate widget to hold the text, but that still results in a small area around the check box that responds to clicks.
Two solutions come to mind:
Do as you suggest and create a separate widget for the checkbutton and for the label.
replace the bindings on the checkbutton with your own, and examine the x/y coordinates of the click and only accept the click if it happens in a small region of the widget.
This program creates a checkbutton and overrides the default event on it by binding a method to the checkbutton. When the button is clicked, the method checks a defined limit to allow the normal operation or to override. OP wanted to make sure that when text of the checkbutton is clicked, no default action is taken. That is essentially what this does.
import tkinter as tk
import tkinter.ttk as ttk
class App(tk.Frame):
def __init__(self, parent, *args, **kwargs):
self.checkvar = IntVar()
check = tk.Checkbutton(parent, text='Click', variable=self.checkvar)
check.bind('<Button-1>', self.checkCheck)
check.pack()
print(dir(check))
def checkCheck(self, event):
# Set limit based on your font and preference
limit = 18
print(event.x, event.y, self.checkvar.get())
if event.x > limit or event.y > limit:
self.checkvar.set(not self.checkvar.get())
else:
print("Normal behavior")
if __name__ == "__main__":
window = tk.Tk()
app = App(window)
window.mainloop()

Categories

Resources