I am trying to add a scrollbar to my GUI and found a pretty nice tutorial on youtube. Even when he uses pack in the code, there is a comment which translates the code to make it able to use it with place. I made a few adaptions but it didn't work, only the (non-functional) arrows and the background of the scrollbar appear as you can see here. I've tried some other solutions in SO like
Scrollbar in Canvas doesn't work - Tkinter Python
Tkinter scrollbar not appearing
So here is what I tried so far:
import tkinter as tk
from tkinter import ttk
window1.destroy() # previous window where user enters meta data
input_window= tk.Tk()
input_window.geometry(str(width) + 'x' + str(height)) # height=840, width=480
# Adding a Full Screen ScrollBar - Python Tkinter GUI Tutorial #96 https://youtu.be/0WafQCaok6g">
# Create canvas
my_canvas = tk.Canvas(input_window, width=width, height=height)
my_canvas.place(x=0, y=0)
# creating frame
main_frame = tk.Frame(my_canvas, width=width, height=height)
main_frame.place(x=0, y=0)
# Add A Scrollbar To The Canvas
my_scrollbar = ttk.Scrollbar(input_window, orient='vertical', command=my_canvas.yview)
my_scrollbar.place(x=width-20, y=0, height=height)
# Configure The Canvas
my_canvas.configure(yscrollcommand=my_scrollbar.set)
my_canvas.bind('<Configure>', lambda e: my_canvas.configure(scrollregion=my_canvas.bbox("all")))
def _on_mouse_wheel(event): # scrolling mousewheel
my_canvas.yview_scroll(-1 * int((event.delta / 120)), "units")
my_canvas.bind_all("<MouseWheel>", _on_mouse_wheel)
# Create ANOTHER Frame INSIDE the Canvas
second_frame = tk.Frame(my_canvas, width=width, height=height)
# Add that New frame To a Window In The Canvas
my_canvas.create_window((0, 0), window=second_frame, anchor="nw")
...
window1.mainloop() # previous window
My guess is, that the window is larger than the height of 840 because I can only see the upper arrow of the grey scrollbar. If I enlarge the window I can see the lower arrow of the gray scrollbar but the bar never appears.
Thanks in advance for your help!
Related
am trying to make a notepad app and I wanted to add a small bar at the end with buttons to do custom stuff but when I try to add a button it doesn't appear on the program what did I do wrong?
here is the script
from gc import callbacks
import re
from tkinter import *
from tkinter import ttk
import time
from turtle import right
root = Tk()
root.title('Notepad')
root.iconbitmap('C:/notes.ico')
root.geometry("500x500")
root.tk.call("source", "C:/Users/Hero/Documents/Visual Studio code/My project/azure.tcl")
root.tk.call("set_theme", "dark")
def change_theme():
if root.tk.call("ttk::style", "theme", "use") == "azure-dark":
root.tk.call("set_theme", "light")
else:
root.tk.call("set_theme", "dark")
style=ttk.Style()
style.theme_use('azure-dark')
style.configure("Vertical.TScrollbar", background="grey", bordercolor="black", arrowcolor="white")
scroll = ttk.Scrollbar(root, orient='vertical')
scroll.pack(side=RIGHT, fill='y')
text=Text(root, font=("Georgia, 24"), yscrollcommand=scroll.set, bg='#292929')
scroll.config(command=text.yview)
text.pack()
#button am talking about
fonts = ttk.Button(root, text='Size and Font', style='Accent.TButton')
fonts.pack()
root.mainloop()
Update: It worked when i had the buttons at the top but at the bottom it doesn't show up
The text box is too tall for a window with size 500x500, so the button below the text box is out of the viewable area of the window.
You can set the width and height options of the text box to a smaller values and use text.pack(fill='both', expand=1)` to expand the text box to fill the window:
# set width and height to smaller values
text = Text(root, font=("Georgia, 24"), yscrollcommand=scroll.set, bg='#292929', width=1, height=1)
# then expand it to fill the window
text.pack(fill='both', expand=1)
i fixed by adding a frame then making it at the bottom then putting the button at this frame thanks everyone that tried to help
I'm writing an application in tkinter which has the following structure:
Notebook
Tab (frame on the notebook)
Canvas (on the frame)
SecondFrame (on the canvas) ← this is where I want to pack my buttons
MyButtons (on second frame)
While scrollbar is linked as expected to my canvas.
Lets say I have 20 buttons when running the program and by pressing any of them I want to destroy the last button
This is my code:
from tkinter import *
from tkinter.ttk import *
root = Tk()
root.geometry('300x300')
root.title('Update Scrollbar')
notebook = Notebook(root)
tab1 = Frame(notebook)
notebook.add(tab1, text='Home')
notebook.pack(expand=1, fill='both')
canvas = Canvas(tab1)
second_frame = Frame(canvas)
scrollbar = Scrollbar(tab1, orient='vertical', command=canvas.yview)
canvas.create_window((0, 0), window=second_frame, anchor='center')
scrollbar.pack(side='right', fill='y')
canvas.config(yscrollcommand=scrollbar.set)
canvas.bind('<Configure>', lambda e: canvas.configure(scrollregion=canvas.bbox('all')))
canvas.pack()
# With this function I destroy the last button:
def delete_buttons():
list(second_frame.winfo_children())[-1].destroy()
second_frame.update_idletasks()
# Here I pack my buttons all with a command 'delete_buttons'
for i in range(20):
Button(second_frame, text='Button' + str(i), command=delete_buttons).pack()
root.mainloop()
However when clicking on a button, the last button is destroyed but an ugly space is created in the top and bottom of the window. (Because of a missing button that took space before I suppose.)
The space is appearing because of the anchor= option you're using to create the Canvas window object:
canvas.create_window((0, 0), window=second_frame, anchor='center')
Which causes the contents to be re-centered every time one of the Buttons is deleted.
To prevent some of the extra space resulting from the deletion from getting distributed to the top of the Canvas, simply anchor the window object to its NorthWest (upper left) corner like this:
canvas.create_window((0, 0), window=second_frame, anchor='nw')
Also note that second_frame.update_idletasks() call in the delete_buttons() function isn't necessary.
I was working on a project and I want to make fixed position with window size I mean if the window resized the position of that widget will be increase \ decrease .
Help
I made this :
but If I increase size of the window look :
the button will be in the same position 😢
Code :
from tkinter import *
from tkinter import ttk
import os
edt_win = Tk()
edt_win.geometry("1280x720")
edt_win.title("Tkinter Editor")
edt_win.minsize(width=900, height=700)
mainfont = ("comic sans ms",10,"bold")
add_obj_menu_frm = Frame(width=200,height=200,relief=SUNKEN,borderwidth=4)
add_obj_menu_frm.pack(side=LEFT,fill=BOTH,ipady=200,pady=50)
def add_obj_layout():
add_btn = ttk.Button(master=edt_win,text="Add")
add_btn.pack(side=BOTTOM,fill=BOTH)
add_btn.place(x=8,y=680)
add_obj_layout()
edt_win.mainloop()
Any Help will be in the heart ♥️
You can use place() for both the frame and the button:
add_obj_menu_frm = Frame(width=200, height=200, relief=SUNKEN, borderwidth=4)
#add_obj_menu_frm.pack(side=LEFT, fill=BOTH, ipady=200, pady=50)
add_obj_menu_frm.place(x=0, y=50, width=200, relheight=1, height=-100) # 50px top and bottom margins
def add_obj_layout():
add_btn = ttk.Button(master=edt_win, text="Add")
add_btn.pack(side=BOTTOM, fill=BOTH)
#add_btn.place(x=8, y=680)
add_btn.place(x=8, rely=1, y=-40) # 40px from the bottom
You are calling the .place() function for your button which fixes the position so it no longer rescales with the application. Try removing that part - the pack() method anyway takes care of drawing your button for you.
I am trying to make an application that displays a grid in the middle of the screen surrounded by two bars, a top bar and a bottom bar, which contain buttons for the user to press. These buttons should be able to display no matter where the user scrolls to on the grid and should not be cut off if the window is resized. I am struggling to configure the scrollbar to track the right area and to have the grid fall off the screen when the window is resized. Here is my code so far:
from tkinter import *
def add_row(event):
input_row = Entry(grid_frame, bd=1, text="", bg="white", relief="solid")
input_row.grid(row=grid_frame.rows, sticky=N+S+E+W)
Grid.rowconfigure(grid_frame, grid_frame.rows, weight=1)
grid_frame.rows = grid_frame.rows + 1
class GridFrame(Frame):
rows = 0
def __init__(self, root):
Frame.__init__(self, root, bd=1)
root = Tk(className="Main screen")
root.minsize(408, 80)
# size to quarter of screen
w, h = root.winfo_screenwidth() / 2, root.winfo_screenheight() / 2
root.geometry("%dx%d+0+0" % (w, h))
# grid_frame will resize and bars will not
Grid.rowconfigure(root, 1, weight=1)
Grid.columnconfigure(root, 0, weight=1)
myframe = Frame(root, bd=4, relief="groove")
myframe.grid(row=1, sticky=N + W + S + E)
canvas = Canvas(myframe)
grid_frame = GridFrame(canvas)
grid_frame.pack(fill=BOTH, expand=True)
grid_frame.bind("<Button-1>", add_row)
scrollbar = Scrollbar(myframe, orient="vertical", command=canvas.yview)
canvas.configure(yscrollcommand=scrollbar.set)
scrollbar.pack(side=RIGHT, fill=Y)
canvas.pack(side=LEFT, fill=BOTH, expand=True)
topBar = Frame(root, grid_frame)
label = Label(topBar, text="Top Text")
label.pack()
topBar.grid(row=0, sticky=W+N+E+S)
bottomFrame = Frame(root, grid_frame)
label = Label(bottomFrame, text="Bottom Text")
label.pack()
bottomFrame.grid(row=2, sticky=E+S+W)
mainloop()
The scrollregion I want to track is the myframe/canvas/grid_frame combination I read to use from this post. The current functionality is that the scrollbar is never in an "active" state and rows added to the grid merely shrink the grid for it to fit within the display. To add a new row, click within the grid_frame region. Any help would be greatly appreciated! Here are some images of the current UI:
UI display with only a few rows
UI display with many more rows
There are two major problems with your code.
First, for the canvas to be able to scroll the inner frame, the inner frame must be a canvas object created with create_window. You're adding it to the canvas with pack, which means the canvas cannot scroll it.
To fix that, use create_window instead of pack:
canvas.create_window(0, 0, anchor="nw", window=grid_frame)
Second, you must reset the scrollregion attribute whenever the contents inside the canvas change. Normally this is done in a <Configure> event handler on the frame, but you can just as easily call it in your add_row function.
For example, add the following line to the end of add_row:
canvas.configure(scrollregion=canvas.bbox("all"))
With those two changes, the scrollbars will start to work as soon as the inner frame is taller than the canvas.
The above solves the problem of the inner window being able to scroll when you add items. In the specific example of this test program, you also have the problem that your binding is on the frame. At startup the frame has a size of 1x1 so it's a bit hard to click on. Moving the binding to the canvas will make this specific demo program work better.
So I have a little issue with a gui in tk (python, code below), the problem being that my scrollbar seems not to be linked to my canvas, though i think i asked it properly ... any hint ?
root = tk.Tk() # window
root_frame = tk.Frame(root) # main container
root_frame.pack()
container_frame = tk.Frame(root_frame) # specific container
container_frame.pack(fill="both")
inner_canvas = tk.Canvas(container_frame, width=100, height=100) # contains the widgets
inner_canvas.grid_propagate(False) # i heard this is necessary ...
inner_scrollbar = tk.Scrollbar(container_frame, command=inner_canvas.yview)
inner_canvas.configure(yscrollcommand=inner_scrollbar.set)
inner_canvas.pack(fill="both", side="left")
inner_scrollbar.pack(fill="y", side="right")
for k in range(100): # simulate the homemade widgets i want to add.
tk.Label(inner_canvas, text=str(k)+" row").grid(row=k, rowspan=1, columnspan=1)
root.mainloop()
The canvas scrollbar will only scroll widgets added to the canvas with create_window. It will not scroll widgets added to the canvas with pack, place or grid.