tkinter how to auto scroll verticallly when I press the button - python

I want to know 3 things.
First thing is when I move my mouse to the middle of the frame and use the scroll wheel on the mouse it doesn't have any effect.
Second I want to press a button that scroll to a y position that I want. I know there is something like event.y but I don't know how to change it.
Last is there a way to use right click to auto scroll to the button that I selected. Thanks.
from tkinter import ttk
root=Tk()
root.geometry("500x400")
root.grid_columnconfigure(0, weight=1)
root.grid_rowconfigure(0, weight=1)
mf=Frame(root)
mf.pack(fill=BOTH, expand=1)
mc=Canvas(mf)
mc.pack(side=LEFT, fill=BOTH, expand=1)
ms=ttk.Scrollbar(mf,orient= VERTICAL,command=mc.yview)
ms.focus_set()
ms.pack(side=RIGHT,fill=BOTH)
mc.bind('<Configure>', lambda e:mc.configure(scrollregion=mc.bbox("all")))
mc.configure(yscrollcommand=ms.set,scrollregion=mc.bbox("all"))
sf=Frame(mc)
mc.create_window(0,0,window=sf,anchor='n')
for th in range(100):
Button(sf,text=f'Button {th}YO!').grid(row=th,column=0,pady=10,padx=10)#pad is distance
root.mainloop()

Related

Tkinter: How to resize a scroll bar if the canvas changes size?

I am working on a project where I need to display information when a button is clicked, and hide information when that button is clicked again. The information can be several rows and extend beyond the window, so I am trying to add a scroll bar to get around this issue. The problem is that when the information is displayed, the scroll bar does not show. Scrolling is still possible but the actual bar is not there. Resizing the window fixes this issue for some reason. Also when the button is clicked again to hide the information, the size of the canvas and the scrollbar remain the same, so you can scroll far beyond the button into empty space. My theory is that the scroll region is not updating when the widgets in the canvas change size - but I'm not sure how to go about fixing that.
I realize this explanation may be a bit confusing, so I have provided a simplified example below. This example has a single button that when clicked reveals several lines of "other info". The scrollbar and/or canvas does not resize properly upon interacting with this button.
My strategy right now was to have a method called add_scrollbar that removes the current scrollbar and creates a new one every time the widgets change in hopes that the new one would be the right size; however this still is not working.
from tkinter import *
from tkinter import ttk
def add_scrollbar(outer_frame, canvas):
if len(outer_frame.winfo_children()) == 2:
# canvas is at index 0 of the outer frame, if a scrollbar has been added it will be at index 1
outer_frame.winfo_children()[1].destroy()
# my strategy here was to destroy the existing scroll bar
# and create a new one each time the widget changes size
scrollbar = ttk.Scrollbar(outer_frame, orient=VERTICAL, command=canvas.yview)
scrollbar.pack(side=RIGHT, fill=Y)
canvas.configure(yscrollcommand=scrollbar.set)
canvas.bind('<Configure>', lambda e: canvas.configure(scrollregion=canvas.bbox("all")))
return
def create_example():
root = Tk()
root.geometry("1200x1200")
my_outer_frame = Frame(root)
my_outer_frame.pack(fill=BOTH, expand=1)
my_canvas = Canvas(my_outer_frame)
my_canvas.pack(side=LEFT, fill=BOTH, expand=1)
inner_frame = Frame(my_canvas)
my_canvas.create_window((0, 0), window=inner_frame)
# ^^^ Sets up the ability to have a scroll_bar
changing_frame = Frame(inner_frame, borderwidth=4) # this is the frame that will be changing its contents
changing_frame.pack(side=LEFT, anchor="n")
display_frame(changing_frame, my_outer_frame, my_canvas)
# this method re-displays the changing frame depending on the specified size ('big' or 'small'
root.mainloop()
return
def display_frame(frame, outer_frame, canvas, size='small'):
for widget in frame.winfo_children():
widget.destroy()
if size == 'small':
Button(frame, height=5, width=5, text="Show",
command=lambda this_frame=frame: display_frame(this_frame, outer_frame, canvas, size='big')).grid(row=0,
column=0)
elif size == 'big':
Button(frame, height=5, width=5, text="Hide",
command=lambda this_frame=frame: display_frame(this_frame, outer_frame, canvas, size='small')).grid(
row=0, column=0)
for n in range(1, 100):
Label(frame, text="Other Stuff!").grid(row=n, column=0)
frame.pack(side=LEFT)
add_scrollbar(outer_frame, canvas) # this method is supposed to destroy the existing scrollbar and make a new one
return
if __name__ == '__main__':
create_example()

Tkinter Enter and Motion bindings

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

How can I get the Temperature to display in the top left corner while having the time and date in the top right?

I have a time, date, and weather widget I need to display in each top corners. The time displays correctly but the weather won't stay in the top left corner. I used python to code this and no matter where i anchor the weather wont go to the top left corner. I am a bit new to Tkinter so please help me and explain. THIS IS FOR SCHOOL PROJECT PLS HELP
Picture of my program
root = Tk()
#BACKGROUND
root.configure(bg="black")
#ORGANIZATION
topFrame=Frame(root,bg="black")
topFrame.pack(side=TOP,fill=BOTH)
bottomFrame=Frame(root,bg="black")
bottomFrame.pack(side=BOTTOM,fill=BOTH)
#CLOCK WIDGET
widget=Label(topFrame,font=("helvitic",large_text_size,"bold",),bg="black",fg="white")
widget.pack(side=TOP,anchor=E)
Clock()
#DAY OF THE WEEK
day_label=Label(topFrame,font=("helvitic",small_text_size,"bold"),bg="black",fg="white")
day_label.pack(side=TOP,anchor=E)
Day_Week()
#DATE
date_label=Label(topFrame,font=("helvitic",small_text_size,"bold"),bg="black",fg="white")
date_label.pack(side=TOP,anchor=E)
Date()
#WEATHER
weather_label=Label(topFrame,font=("helvitic",50,"bold"),bg="black",fg="white",)
weather_label.pack(side=LEFT,anchor=NW)
Weather()
Celscius=Label(topFrame,font=("helvitic",xlarge_text_size,"bold"),bg="black",fg="white",text="°C")
Celscius.pack(side=LEFT,anchor=N)
#WEATHER ICON
icon_label=Label(bottomFrame,font=("helvitic",50,"bold"),bg="black",fg="white",)
icon_label.pack(side=LEFT)
Icon()
#FULLSCREEN AND EXIT
root.bind("<Delete>",exit)
root.bind("<Return>",fullscrn)
root.bind("<Escape>",bckspace)
root.mainloop()
[1]: https://i.stack.imgur.com/YbiLh.png
For a layout like this, I find it easier to use the grid geometry manager instead of pack.
With the grid manager, you are packing your widgets into columns and rows, instead of side by side or on top of each other. You can configure where the widget sits in it's area of the grid, how the grid should respond to the window resizing etc.
This code puts a label in the top left, top right and bottom left of a window. They will stay there even if the window is resized.
import tkinter as tk
root = tk.Tk()
# configure the grid for resizing
root.grid_columnconfigure(0, weight=1)
root.grid_columnconfigure(1, weight=1)
root.grid_rowconfigure(0, weight=1)
root.grid_rowconfigure(1, weight=1)
# pack labels
tk.Label(root, text='TL').grid(row=0, column=0, sticky='NW')
tk.Label(root, text='TR').grid(row=0, column=1, sticky='NE')
tk.Label(root, text='BL').grid(row=1, column=0, sticky='SW')
root.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()

Why does this scrollbar not work after inserting widgets into a listbox?

Basically, I am trying to add a scrollbar to a window containing widgets. I am able to successfully add a scrollbar to a Listbox widget and after inserting stuff, the program works just the way I want it to. But, I face a problem when I place widgets into the Listbox. The scrollbar appears but it seems to be disabled.
from tkinter import *
root = Tk()
root.geometry("640x480")
root.resizable(0,0)
myscrollbar = Scrollbar(root)
myscrollbar.pack(side=RIGHT, fill=Y)
mylist = Listbox(root, width=640, height=480, yscrollcommand=myscrollbar.set)
mylist.pack(fill=BOTH, expand=True)
for x in range(1, 101):
mylist.insert(END, Label(mylist, text="Label: "+str(x)).grid(row=x, column=0))
myscrollbar.config(command = mylist.yview)
root.mainloop()
Any way to fix this code?
from tkinter import *
def myScrollcmd(event):
mycanvas.config(scrollregion=mycanvas.bbox('all'))
root = Tk()
mycanvas = Canvas(root)
mycanvas.pack(fill=BOTH, expand=True)
myFrame = Frame(mycanvas)
mycanvas.create_window((0, 0), window=myFrame, anchor=NW)
myScrollbar = Scrollbar(mycanvas, orient=VERTICAL, command=mycanvas.yview)
myScrollbar.pack(side=RIGHT, fill=Y)
mycanvas.config(yscrollcommand=myScrollbar.set)
mycanvas.bind("<Configure>", myScrollcmd)
for x in range(100):
Label(myFrame, text="Text "+str(x)).pack()
root.mainloop()
This works. However, there is one problem that might not be a major one. The problem is, when my cursor is on the canvas, and I'm moving my mouse wheel, the scrollbar doesn't budge. However the scroll bar moves along with my mouse wheel when my cursor is on top of the scroll bar. I can drag the scroll box to scroll up and down and use the scroll buttons to scroll up and down but the mouse wheel only works when my cursor is hovering over the scrollbar widget.

Categories

Resources