My code:
import tkinter as tk
root = tk.Tk()
for i in range(50):
for j in range(50):
tk.Button(height=1, width=2, bg='Blue').grid(row=j, column=i)
root.mainloop()
I can not see all of the buttons in the screen even when I maxmize the window. so I want to add an option to zoom out (all of the widgets will be smaller) so I can see all of them. How do I do that?
Example code:
import tkinter as tk
root = tk.Tk()
root.state('zoomed')
widgets_to_zoom_list = []
DEFAULT_SIZE = 50
def zoom(widget):
for every_widget in widgets_to_zoom_list:
every_widget.config(width=widget.get(), height=widget.get())
def main():
canvas = tk.Canvas(root)
frame = tk.Frame(canvas)
zoom_scale = tk.Scale(root, orient='vertical', from_=1, to=100)
zoom_scale.config(command=lambda args: zoom(zoom_scale))
zoom_scale.set(DEFAULT_SIZE)
pixel = tk.PhotoImage(width=1, height=1)
for i in range(50):
btn = tk.Button(frame, text=str(i + 1), bg='Blue', image=pixel, width=DEFAULT_SIZE, height=DEFAULT_SIZE, compound="c")
btn.grid(row=0, column=i)
widgets_to_zoom_list.append(btn)
canvas.create_window(0, 0, anchor='nw', window=frame)
# make sure everything is displayed before configuring the scroll region
canvas.update_idletasks()
canvas.configure(scrollregion=canvas.bbox('all'))
canvas.pack(fill='both', side='left', expand=True)
zoom_scale.pack(fill='y', side='right')
root.mainloop()
if __name__ == '__main__':
main()
From what i have been able to understand from your question, i think you want the window to be resizable in tkinter.
To allow a window to be resized by the user, we use the resizable function -:
root.resizable(height = True, width = True)
In this case the two args are height and width which help you customize if you only want the widget to be vertically resizable or only want it to be horizontally resizable.
Your code with this function added should look like this -:
import tkinter as tk
root = tk.Tk()
root.resizable(True, True) #Assuming you want both vertically and horizontally resizable window.
for i in range(50):
for j in range(50):
tk.Button(height=1, width=2, bg='Blue').grid(row=j, column=i)
root.mainloop()
I hope this will solve your problem.
And I also hope you are safe in this time of an ongoing pandemic.
Related
Minimal reproducable Example
from tkinter import *
def test(event):
print(event.widget)
window = Tk()
window.geometry("600x600")
window.bind("<Motion>", test)
frame = Frame(window, bg="red", width=200, height=200)
frame.pack()
frame.bind("<Motion>", test)
window.mainloop()
I want to call the function "test" from different widgets when i move over them. Instead of that, when i hover over the frame, both the window and the frame print that im hovering over the frame, which is not the behaviour i need. Can someone help me achieve the right behaviour?
I think your confusion is in the moment of interpreting when the mouse pointer entered the widget or left the widget. Instead of Motion let's use for example Leave and Enter events to better understand what happens.
I have taken the liberty of including some labels that show which widget we enter and left at each moment.
from tkinter import *
def test_enter(event):
enter.set(event.widget)
def test_left(event):
left.set(event.widget)
window = Tk()
window.geometry("300x300")
window.bind("<Enter>", test_enter)
window.bind("<Leave>", test_left)
frame = Frame(window, bg="red", width=200, height=200)
frame.pack()
frame.bind("<Enter>", test_enter)
frame.bind("<Leave>", test_left)
label1 = Label(frame, text="Enter")
label1.place(relx=0.1, rely=0.4, x= 0.2, y=0.2)
enter = StringVar()
label_enter = Label(frame, textvariable=enter)
label_enter.place(relx=0.3, rely=0.4, x= 0.6, y=0.2)
label2 = Label(frame, text="Leave")
label2.place(relx=0.1, rely=0.6, x= 0.2, y=0.2)
left = StringVar()
label_left = Label(frame, textvariable=left)
label_left.place(relx=0.3, rely=0.6, x= 0.6, y=0.2)
window.mainloop()
Remember that the Frame is inside the Window. I mean that when you enter the Window you have not left root Window, you will continue to be in Window. Or if you enter inside a Label you have not left the Frame.
You could use lambda to pass the widget when the function is run
def test(event, widget):
print(widget)
window = Tk()
window.geometry("600x600")
window.bind("<Motion>", test)
frame = Frame(window, bg="red", width=200, height=200)
frame.pack()
frame.bind("<Motion>", lambda: test(frame))
window.mainloop()
You just need to change two lines
def test(event, widget):
print(widget)
and
frame.bind("<Motion>", lambda: test(frame))
I am trying to add a scroll bar into my tkinter application. It is appearing, however it is greyed out and is not able to scroll and I am not sure why despite the fact that I have many widgets beyond the height of the page. Any help would be appreciated.
import calendar
import tkinter as tk
from tkinter import ttk
root = tk.Tk()
root.geometry('800x800')
x = 30
y = 30
box_image = tk.PhotoImage(file='apple.png')
### SCROLL BAR ###
# create a main frame
main_frame = tk.Frame(root)
main_frame.pack(fill='both', expand=1)
# create a canvas
my_canvas = tk.Canvas(main_frame)
my_canvas.pack(side='left', fill='both', expand=1)
# add a scrollbar to the canvas
my_scrollbar = ttk.Scrollbar(main_frame, orient='vertical', command=my_canvas.yview)
my_scrollbar.pack(side='right', fill='y')
# configure the canvas
my_canvas.configure(yscrollcommand=my_scrollbar.set)
my_canvas.bind('<Configure>', lambda e: my_canvas.configure(scrollregion = my_canvas.bbox("all")))
# create Another frame inside the canvas
second_frame = tk.Frame(my_canvas)
# add that new frame to a window in the canvas
my_canvas.create_window((0,0), window=second_frame, anchor="nw")
def display():
global x , y
panel2 = tk.Label(main_frame, image=box_image, bg='#f7f6f6')
panel2.place(x=x, y=y)
x = x
y = y+200
button = tk.Button(main_frame, text="click me", command=display)
button.place(x=0, y=0)
for thing in range (100):
tk.Button(main_frame, text=f'Button {thing}Yo!').pack()
root.mainloop()
For the frame-in-a-canvas trick to work, you must add the buttons to the inner frame:
for thing in range (100):
tk.Button(second_frame, text=f'Button {thing}Yo!').pack()
# ^^^^^^^^^^^^
I want to fit this frame with scrollbar(refer the provided image) in the black space present in the provided image. How do I do that. The frame should totally cover the black space.
The code for program.The image
from tkinter import *
from tkinter import ttk
C = Tk()
C.maxsize(1200, 750)
C.geometry("1200x750")
C.title("Mainscreen")
style = ttk.Style()
style.theme_use('clam')
BG = PhotoImage(file="Mainscreen bg.png")
ML = PhotoImage(file="Music_label.png")
BG_label = Label(C, image=BG, border=0)
BG_label.place(x=0, y=0)
style.configure("Vertical.TScrollbar", gripcount=0,
background="Cyan", darkcolor="gray6", lightcolor="LightGreen",
troughcolor="Turquoise4", bordercolor="gray6", arrowcolor="gray6",arrowsize=15)
wrapper1= LabelFrame(C, width="1600", height="100", background="gray6",bd=0)
mycanvas = Canvas(wrapper1,background="gray6",borderwidth=0, highlightthickness=0, width=700, height=600)
mycanvas.pack(side=LEFT, expand="false", padx=0)
yscrollbar = ttk.Scrollbar(wrapper1, orient="vertical",command=mycanvas.yview)
yscrollbar.pack(side=RIGHT, fill="y")
mycanvas.configure(yscrollcommand=yscrollbar.set)
mycanvas.bind('<Configure>',lambda e: mycanvas.configure(scrollregion=mycanvas.bbox("all")))
myframe = Frame(mycanvas)
mycanvas.create_window((0,0), window=myframe, anchor="n")
wrapper1.pack(side=RIGHT,expand="false", padx=0, pady=200)
for i in range(50):
Button(myframe, image=ML,bg="gray6",bd=0).pack()
mainloop()
EDIT:
Music_Label
Mainscreen bg
So after trying to understand the underlying problem for a while I have reached the conclusion, that the problem is with the fact that the button are being drawn in the myframe and the myframe is outside the mycanvas which contains the scrollbar. So by changing the master widget for the button from myframe to mycanvas, the problem gets fixed now the scrollbar is adjacent to the buttons. BUT, Also now the button r shifted the side since while packing the wrapper1, you did side = RIGHT, so I would also suggest that you use place here instead of pack, since pack depends on the space available and is not reliable if you are using a Background for your GUI and want the buttons within a portion of it.
I have changed the following lines -:
Button(mycanvas, image=ML,bg="gray6",bd=0).pack() # Changed to mycanvas from myframe
and
wrapper1.place(x = {YOUR X, WHERE THE BOX STARTS}, y = {YOUR Y, WHERE THE BOX STARTS}) # Use place instead..
You can use pack also, and change the padx and pady arguments but it will be tricky to get it to work always as expected.
The fixed code is this -:
from tkinter import *
from tkinter import ttk
C = Tk()
C.maxsize(1200, 750)
C.geometry("1200x750")
C.title("Mainscreen")
style = ttk.Style()
style.theme_use('clam')
BG = PhotoImage(file="Mainscreen bg.png")
ML = PhotoImage(file="Music_label.png")
BG_label = Label(C, image=BG, border=0)
BG_label.place(x=0, y=0)
style.configure("Vertical.TScrollbar", gripcount=0,
background="Cyan", darkcolor="gray6", lightcolor="LightGreen",
troughcolor="Turquoise4", bordercolor="gray6", arrowcolor="gray6",arrowsize=15)
wrapper1= LabelFrame(C, width="1600", height="100", background="gray6",bd=0)
mycanvas = Canvas(wrapper1,background="gray6",borderwidth=0, highlightthickness=0, width=700, height=600)
mycanvas.pack(side=LEFT, expand=False, padx=0)
yscrollbar = ttk.Scrollbar(wrapper1, orient="vertical",command=mycanvas.yview)
yscrollbar.pack(side=RIGHT, fill="y", expand = False)
mycanvas.configure(yscrollcommand=yscrollbar.set)
mycanvas.bind('<Configure>',lambda e: mycanvas.configure(scrollregion=mycanvas.bbox("all")))
myframe = Frame(mycanvas)
mycanvas.create_window((0,0), window=myframe, anchor="n")
wrapper1.pack(expand=True, padx=0, pady=200) # Use place instead
for i in range(50):
Button(mycanvas, image=ML,bg="gray6",bd=0).pack() # Change this to mycanvas from myframe
mainloop()
I would like the buttons to be placed in random points of the root. I do not understand why they all stack in the middle, since I think I am placing them at random x and y
import tkinter as tk
from tkinter import *
from random import randint
num_buttons = int(input("How many buttons do you want?"))
buttons = [0] * num_buttons
root = tk.Tk()
canvas = tk.Canvas(root, height=700, width=700, bg="dark slate grey")
canvas.pack()
frame = tk.Frame(root, bg="red")
frame.place(relheight=0.6, relwidth=0.6, rely=0.2, relx=0.2)
for k in range(num_buttons):
randx = int(randint(-100,100))
randy = int(randint(-100,100))
buttons[k] = tk.Button(frame, text="DO NOT CLICK ME",
fg="Black", highlightbackground="orange",
command=you_clicked)
buttons[k].place(x=randx, y=randy)
buttons[k].pack()
root.mainloop()
You should not be calling both place and pack. Only one geometry manager can control a widget. When you call pack, any effect a previous call to place is thrown away.
I am newbie in programming, don't hate me pls :)
Why scroll is not working on my canvas widget?
I added loop with 30 rows and I cannot scroll down.
Its look like it because of create_text() method or maybe not.
I've written code for example below.
from tkinter import *
root = Tk()
root.geometry('200x150')
frame = Frame(root)
yscrollbar = Scrollbar(frame, orient=VERTICAL)
yscrollbar.pack(fill=Y, side=RIGHT)
canvas = Canvas(frame,
yscrollcommand=yscrollbar.set,
bg='white')
canvas.pack(fill=BOTH)
yscrollbar.config(command=canvas.yview)
n=12
for i in range(1,31):
canvas.create_text(10,n,text=i)
n+=12
frame.pack()
root.mainloop()
Scrolling is not responsive because you need to tell the canvas to limit the scrolling to a given area.
You can use the bbox method to get a bounding box for a given object, or a group of objects.
canvas.bbox(ALL) returns the bounding box for all objects on the canvas.
Link: http://effbot.org/zone/tkinter-scrollbar-patterns.htm you can check other methods to do this in this link
Here is the working code:
from tkinter import *
root = Tk()
root.geometry('200x150')
frame = Frame(root)
yscrollbar = Scrollbar(frame, orient=VERTICAL)
yscrollbar.pack(fill=Y, side=RIGHT)
canvas = Canvas(frame,
yscrollcommand=yscrollbar.set,
bg='white')
canvas.pack(fill=BOTH)
yscrollbar.config(command=canvas.yview)
n=12
for i in range(1,31):
canvas.create_text(10,n,text=i)
n+=12
frame.pack()
# Add this line to tell the canvas the area over to scroll
canvas.config(scrollregion=canvas.bbox(ALL))
root.mainloop()