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

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.

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()

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 do you change the state of multiple tkinter buttons when your mouse is pressed and hovering over it?

I have a 2d array of tkinter buttons.
It looks like this:
I want to be able to click on a button, hold my mouse down, and every button that is hovered over while my mouse is pressed down changes colors. So far I have it to the point where if you hover over any square regardless if a mouse button is pressed it changes colors.
The code looks like this so far:
def draw(self, i, j):
button = self.buttons[i][j]
button.bind('<Enter>', lambda event: self.on_enter(event, button))
def on_enter(self, e, button):
button['background'] = 'green'
To be clear, I want to be able to change a button's color when left-click is held down and a button is hovered over at the same time.
Thanks for helping me.
EDIT: removed picture of code and provided something that can be copy and pasted.
2ND EDIT: the code is about 100 lines, but the gist is there's a 2d array of tkinter buttons, and the code I provided shows the 2 functions responsible for changing the color of the buttons. If more code is needed, I'll put it in.
You can bind <B1-Motion> on root window to a callback. Then inside the callback, use .winfo_pointerxy() to get the mouse position and .winfo_containing() to find which button is under the mouse pointer and change its background color:
Example:
def on_drag(event):
x, y = root.winfo_pointerxy()
btn = root.winfo_containing(x, y)
if btn:
btn.config(bg="green")
# root is the root window
root.bind('<B1-Motion>', on_drag)

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()

How to bind spacebar key to a certain method in tkinter (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.

Categories

Resources