Tkinter Enter and Motion bindings - python

Is it possible to track what widgets I enter with my mouse into while it's pressed?
I want to create a chain-like effect that the background of the label\button change while click and drag the mouse and moving from widget to widget.
Thanks :)

You can bind to the <B1-Motion> event, and then use winfo_containing to get the widget under the cursor.
Here's a simple example:
import tkinter as tk
root = tk.Tk()
current_label = tk.Label(root, text="", anchor="w", width=100)
current_label.pack(side="top", fill="x")
def show_widget(event):
widget = event.widget.winfo_containing(event.x_root, event.y_root)
current_label.configure(text=f"widget: {str(widget)}")
for x in range(10):
name = f"Label #{x+1}"
label = tk.Label(root, text=name)
label.pack(padx=10, pady=10)
label.bind("<B1-Motion>", show_widget)
root.mainloop()

I've done stuff like tracking entry/exit for a specific widget:
widget.bind("<Enter>", enter_func)
widget.bind("<Leave>", exit_func)
you may be able to do something cute with that

Related

How to put Scrollbar inside a Listbox in Tkinter?

how can i move the scrollbar inside a listbox? See the photo attached i used a red arrow for explain, here is my code:
from tkinter import *
window = Tk()
window.geometry('500x500')
window.config(bg='#3c3f41')
window.state('zoomed')
frame_listbox = Frame(window,bg='#3c3f41')
frame_listbox.pack(side=LEFT)
listbox = Listbox(frame_listbox,font=('Helvetica',30))
listbox.pack(padx=400)
scrollbar = Scrollbar(window)
scrollbar.pack(side=RIGHT,fill=Y)
scrollbar.config(command=listbox.yview)
listbox.config(yscrollcommand=scrollbar.set)
window.mainloop()
I tried to put a scrollbar inside a Listbox, i expect to understand if it's possible or not
It is recommended to put the scrollbar just to the right of the listbox instead of inside it. To achieve it:
make the scrollbar child of frame_listbox instead of window
move option padx=400 from scrollbar.pack(...) to frame_listbox.pack(...)
pack listbox to the LEFT side
from tkinter import *
window = Tk()
window.geometry('500x500')
window.config(bg='#3c3f41')
window.state('zoomed')
frame_listbox = Frame(window,bg='#3c3f41')
frame_listbox.pack(side=LEFT,padx=400) # added padx=400
listbox = Listbox(frame_listbox,font=('Helvetica',30))
listbox.pack(side=LEFT) # removed padx=400 and added side=LEFT
scrollbar = Scrollbar(frame_listbox) # changed parent to frame_listbox
scrollbar.pack(side=RIGHT,fill=Y)
scrollbar.config(command=listbox.yview)
listbox.config(yscrollcommand=scrollbar.set)
window.mainloop()
Does this will Help? By using grid instead place.
import tkinter as tk
root = tk.Tk()
root.title("Listbox Operations")
# create the listbox (note that size is in characters)
listbox1 = tk.Listbox(root, width=50, height=6)
listbox1.grid(row=0, column=0)
# create a vertical scrollbar to the right of the listbox
yscroll = tk.Scrollbar(command=listbox1.yview, orient=tk.VERTICAL)
yscroll.grid(row=0, column=1, sticky=tk.N+tk.S)
listbox1.configure(yscrollcommand=yscroll.set)
for i in range(1, 50):
listbox1.insert(tk.END, i)
root.mainloop()
Result:

How to update values on tkinter window?

I am trying to make a window that would show the location of the mouse at all times by using pyautogui and tkinter. I am new to tkinter and python overall so I am not quite sure how to make it so that the values would keep updating in the window, if it is even possible. Here is my code so far:
from tkinter import *
import pyautogui as pag
window = Tk()
window.geometry("200x200")
window.title("window")
window.config(background="#4ceefc")
coordinates = pag.position()
label1 = Label(window, text="mouse coordinates:")
label1.place(x=20, y=50)
label2 = Label(window, text=coordinates)
label2.place(x=30, y=90)
window.mainloop()
I tried using a while loop on the labels and window.mainloop() function but this did not work
Create a StringVar() to store the coords, and then assign it to the label's textvariable. You can then bind a '<Motion>' handler to your root window to update the label whenever the mouse moves.
coord_var = StringVar(window)
def on_mousemove(event):
coord_var.set(f'Mouse coordinates: {event.x}, {event.y}')
label1 = Label(window, textvariable=coord_var)
label1.place(x=20, y=50)
window.bind('<Motion>', on_mousemove)
Unless you're using pyautogui for something else, you can get away without it for this.

How to open the initial window in tkinter again?

I have a following question. I want to make a button in tkinter that will delete existing changes and the window will looks like the initial window.
This is my initial Window 1:
This is how the window looks like when I click on the first two buttons, Window 2:
Now I would like to click on the "Zpět" button and I want to see Window 1 again.
Here is my code:
import tkinter as tk
root = tk.Tk()
home_frame = tk.Frame(root)
home_frame.grid(row=0, column=0, sticky="news")
def raise_new_payment():
tk.Label(text=f"Stav bilance k 2021-09-09").grid()
def back():
"""I would like to this function to clean everything."""
tk.Label().destroy()
platba = tk.Button(
home_frame,
text="Zadej novou platbu",
command=lambda: raise_new_payment(),
)
platba.pack(pady=10)
zpet = tk.Button(
home_frame,
text="Zpět",
command=back,
)
zpet.pack(pady=10)
I don't know how to use the back() function. I tried to delete the tk.Label as created in raise_new_payment(), but it did not work. Can you help me please? Thanks a lot.
I would suggest you create the label once and don't call .pack() on it first, i.e. it is not visible initially.
Then update it inside raise_new_payment() and call .pack() to show it.
You can call .pack_forget() to hide it again inside back().
import tkinter as tk
root = tk.Tk()
home_frame = tk.Frame(root)
home_frame.grid(row=0, column=0, sticky="news")
def raise_new_payment():
# update label and show it
lbl.config(text=f"Stav bilance k 2021-09-09")
lbl.pack()
def back():
# hide the label
lbl.pack_forget()
platba = tk.Button(
home_frame,
text="Zadej novou platbu",
command=lambda: raise_new_payment(),
)
platba.pack(pady=10)
zpet = tk.Button(
home_frame,
text="Zpět",
command=back,
)
zpet.pack(pady=10)
# create the label and initially hide it
lbl = tk.Label(home_frame)
root.mainloop()

Change color of different widgets altogether in tkinter

I want to change the different configuration colors of different widgets altogether to a same color when the user clicks on the entry widgets.
I've created a function "change_color(color)" where all my widgets are getting configured to the color passed as an argument.
The problem is the code has a lot of widgets and I've to manually add every widget to the function to keep them updated. I can't use a list as some widgets options are different, for eg: changing foreground of entry widget, background of labels, and much more. Please let me know if there is a better approach of doing this.
Here is a small example of my program. My main code is very long and is not suitable to post here.
import tkinter as tk
def change_color(color):
"Change color of widgets."
window.config(bg=color)
user_label.config(bg=color)
pass_label.config(bg=color)
user_entry.config(highlightbackground=color)
pass_entry.config(highlightbackground=color)
user_entry.config(fg=color, insertbackground=color)
pass_entry.config(fg=color, insertbackground=color)
window = tk.Tk()
# username
user_label = tk.Label(window, text='Username')
user_entry = tk.Entry(window, bg='black')
# password
pass_label = tk.Label(window, text='Password')
pass_entry = tk.Entry(window, bg='black')
user_label.grid(row=0, column=0)
user_entry.grid(row=0, column=1)
pass_label.grid(row=1, column=0)
pass_entry.grid(row=1, column=1)
# changes color
user_entry.bind("<1>", lambda _: change_color("#99c9ff"))
pass_entry.bind("<1>", lambda _: change_color("#ffaf99"))
window.mainloop()
I hope you can get an idea from this example. If something is not clear please ask me from the comment section.
You can go through all widgets recursively using winfo_children():
def change_color(color, container=None):
if container is None:
container = window # set to root window
container.config(bg=color)
for child in container.winfo_children():
if child.winfo_children():
# child has children, go through its children
change_color(color, child)
elif type(child) is tk.Label:
child.config(bg=color)
elif type(child) is tk.Entry:
child.config(highlightbackground=color)
child.config(fg=color, insertbackground=color)
# check for other widget types ...
Here is one approach to doing it.
import tkinter as tk
def change_color(color):
"Change color of widgets."
for wdg in window.children():
wdg = window.nametowidget(wdg)
if isinstance(wdg, tk.Label):
wdg.config(bg=color)
elif isinstance(wdg, tk.Entry):
wdg.config(fg=color, insertbackground=color, highlightbackground=color)
window = tk.Tk()
# username
user_label = tk.Label(window, text='Username')
user_entry = tk.Entry(window, bg='black')
# password
pass_label = tk.Label(window, text='Password')
pass_entry = tk.Entry(window, bg='black')
user_label.grid(row=0, column=0)
user_entry.grid(row=0, column=1)
pass_label.grid(row=1, column=0)
pass_entry.grid(row=1, column=1)
# changes color
user_entry.bind("<1>", lambda _: change_color("#99c9ff"))
pass_entry.bind("<1>", lambda _: change_color("#ffaf99"))
window.mainloop()

Tkinter - On which widget is mouse pointer currently?

I want to ask u guys if there is a way of getting name or some id of widget which is mouse pointer currently on. Is there a way of doing this? Thanks for any response.
Normally you get this information from a binding. However, if you want to poll the system at any point to find out which widget is under the mouse, you can use winfo_pointerxy to get the coordinates of the mouse, and then pass those to winfo_containing to get the widget under those coordinates.
Here's an example program that continuously prints out the widget under the mouse:
import tkinter as tk
def print_widget_under_mouse(root):
x,y = root.winfo_pointerxy()
widget = root.winfo_containing(x,y)
print("widget:", widget)
root.after(1000, print_widget_under_mouse, root)
root = tk.Tk()
label_foo = tk.Label(root, text="Foo", name="label_foo")
label_bar = tk.Label(root, text="Bar", name="label_bar")
button = tk.Button(root, text="Button", name="button")
button.pack(side="bottom")
label_foo.pack(fill="both", expand=True)
label_bar.pack(fill="both", expand=True)
print_widget_under_mouse(root)
root.mainloop()

Categories

Resources