I have some code which is creating a scrollable Tkinter canvas with buttons inside. I believe my configuration of the scrollbar and Canvas is ok, but when I run the program, the scrollbar does not scroll. I have looked at other solutions online and I believe I am fulfilling everything that should be applied.
Thank you for any and all help:)
from tkinter import *
root = Tk()
responsesFr = Frame(root, width=700, height=275, bg="#d40b04")
responseFrCoverCanvas = Canvas(root, width=700,height=14 ,highlightthickness=0, border=0,bg="#d40b04")
w = Canvas(responsesFr, width=650, height=225, borderwidth=0,highlightthickness=0,background="white")
w.config(scrollregion=[0,0,1000,225])
for column in range(30):
button1 = Button(w, width=20, height=4)
button1.pack(side='left', padx=25)
if column == 29:
w.config(scrollregion=[0,0,1000,1000])
print("done")
else:
pass
w.pack(padx=25,pady=10)
hbar=Scrollbar(responsesFr, orient=HORIZONTAL)
hbar.pack(padx=25, side=TOP, fill=X)
hbar.config(command=w.xview)
w.config(xscrollcommand=hbar.set)
responsesFr.pack()
root.mainloop()
You can't scroll things added with pack. You must use the canvas create_window method to add widgets to the canvas.
Related
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:
I'm playing around with the scrollbar and the ttk.Notebook functions to create two scrollable tabs. I have the mousewheel bound to scrolling, but it always scrolls both tabs. When you first run the code, you can scroll the first tab by itself because the second tab hasn't been "activated" for lack of a better term. Once you click the second tab to view it, all further scrolling on either tab scrolls both tabs evenly. The scrollbars do work independently when scrolled manually.
Is there a way to only bind the mousewheel to the selected tab at any one time?
Edit: I've noticed another weird behavior that if you resize the window outward everything reacts as it should, but if you resize the window making it narrower, the scrollbar disappears to the right of the now narrower window.
from tkinter import *
from tkinter import ttk
Window = Tk()
# Create the Outer Frame
outer_frame = Frame(Window)
outer_frame.pack(fill=BOTH, expand=1)
# Create and add the tabs
tab_control = ttk.Notebook(outer_frame)
tab1 = ttk.Frame(tab_control)
tab_control.add(tab1, text="Tab 1")
tab2 = ttk.Frame(tab_control)
tab_control.add(tab2, text="Tab 2")
tab_control.pack(expand=1, fill=BOTH)
# Create the canvases
canvas1 = Canvas(tab1)
canvas1.pack(side=LEFT, fill=BOTH, expand=1)
canvas2 = Canvas(tab2)
canvas2.pack(side=LEFT, fill=BOTH, expand=1)
# Add scrollbars to canvases
scrollbar1 = ttk.Scrollbar(tab1, orient=VERTICAL, command=canvas1.yview)
scrollbar1.pack(side=RIGHT, fill=Y)
scrollbar2 = ttk.Scrollbar(tab2, orient=VERTICAL, command=canvas2.yview)
scrollbar2.pack(side=RIGHT, fill=Y)
def _on_mousewheel(event):
canvas1.yview_scroll(int(-1*(event.delta/120)), "units")
canvas2.yview_scroll(int(-1*(event.delta/120)), "units")
# Bind mousewheel to scrollbars
canvas1.bind("<MouseWheel>", _on_mousewheel)
canvas2.bind("<MouseWheel>", _on_mousewheel)
# Configure the canvases scrollbars
canvas1.configure(scrollregion=canvas1.bbox('all'), yscrollcommand=scrollbar1.set)
canvas1.bind('<Configure>', lambda e: canvas1.configure(scrollregion = canvas1.bbox("all")))
canvas2.configure(scrollregion=canvas2.bbox('all'), yscrollcommand=scrollbar2.set)
canvas2.bind('<Configure>', lambda e: canvas2.configure(scrollregion = canvas2.bbox("all")))
# Create frames inside the canvases
inner_frame1 = ttk.Frame(canvas1)
inner_frame2 = ttk.Frame(canvas2)
# Add the frames to the canvases
canvas1.create_window((0,0), window=inner_frame1, anchor="nw")
canvas2.create_window((0,0), window=inner_frame2, anchor="nw")
# Add buttons to the frames
for thing in range(20):
ttk.Button(inner_frame1, text=f'Button {thing}').grid(row=thing, column=0, pady=10, padx=10)
ttk.Button(inner_frame2, text=f'Button {thing}').grid(row=thing, column=0, pady=10, padx=10)
Window.mainloop()
Change the function to this:
def _on_mousewheel(event):
event.widget.yview_scroll(int(-1*(event.delta/120)), "units")
It find the canvas that caught the event and changes its yview_scroll.
I also solved the second problem but I still don't know why exactly. Using this answer I figured out what works and a plausible explanation for it. You have to move your canvas.pack(...) statements after you have packed the scroll bar. So your code should look like this:
from tkinter import *
from tkinter import ttk
Window = Tk()
# Create the Outer Frame
outer_frame = Frame(Window)
outer_frame.pack(fill=BOTH, expand=1)
# Create and add the tabs
tab_control = ttk.Notebook(outer_frame)
tab1 = ttk.Frame(tab_control)
tab_control.add(tab1, text="Tab 1")
tab2 = ttk.Frame(tab_control)
tab_control.add(tab2, text="Tab 2")
tab_control.pack(expand=1, fill=BOTH)
# Create the canvases
canvas1 = Canvas(tab1, bg="orange")
canvas2 = Canvas(tab2, bg="light blue")
# Add scrollbars to canvases
scrollbar1 = ttk.Scrollbar(tab1, orient=VERTICAL, command=canvas1.yview)
scrollbar1.pack(side=RIGHT, fill=Y)
scrollbar2 = ttk.Scrollbar(tab2, orient=VERTICAL, command=canvas2.yview)
scrollbar2.pack(side=RIGHT, fill=Y)
# Pack the canvases after the scrollbar
canvas1.pack(side=LEFT, fill=BOTH, expand=True)
canvas2.pack(side=LEFT, fill=BOTH, expand=True)
# This is the updated even handler:
def _on_mousewheel(event):
event.widget.yview_scroll(int(-1*(event.delta/120)), "units")
# Bind mousewheel to scrollbars
canvas1.bind("<MouseWheel>", _on_mousewheel)
canvas2.bind("<MouseWheel>", _on_mousewheel)
# Configure the canvases scrollbars
canvas1.configure(scrollregion=canvas1.bbox('all'), yscrollcommand=scrollbar1.set)
canvas1.bind('<Configure>', lambda e: canvas1.configure(scrollregion = canvas1.bbox("all")))
canvas2.configure(scrollregion=canvas2.bbox('all'), yscrollcommand=scrollbar2.set)
canvas2.bind('<Configure>', lambda e: canvas2.configure(scrollregion = canvas2.bbox("all")))
# Create frames inside the canvases
inner_frame1 = ttk.Frame(canvas1)
inner_frame2 = ttk.Frame(canvas2)
# Add the frames to the canvases
canvas1.create_window((0,0), window=inner_frame1, anchor="nw")
canvas2.create_window((0,0), window=inner_frame2, anchor="nw")
# Add buttons to the frames
for thing in range(20):
ttk.Button(inner_frame1, text=f'Button {thing}').grid(row=thing, column=0, pady=10, padx=10)
ttk.Button(inner_frame2, text=f'Button {thing}').grid(row=thing, column=0, pady=10, padx=10)
Window.mainloop()
My guess is that when you first pack the canvas with expand=True, fill="both", it decided that it will try to take as much space as possible without thinking about the scrollbar. I don't really know why that happens.
I want to be able to use nested frames but there is a weird behavior : when I enter the height and width parameters they seem to not work. I use .grid() Is that what is causing the problem ? I use ttk Frame, is there some behavior I do not know about ?
I looked at the documentation but nothing seemed to be helping. I tried changing the parameters but I didn't help either.
from tkinter import *
from tkinter import ttk
root = Tk()
root.title("Tk test")
root.geometry("800x800")
frame_1 = ttk.Frame(root, height=400, width=400, relief="sunken")\
frame_1.grid(row=0, column=0, rowspan=1, columnspan=1)
frame_2 = ttk.Frame(frame_1, height=200, width=200, relief="sunken")\
frame_2.grid(row=0, column=0, rowspan=1, columnspan=1, sticky="N, S, W, E")
label_1 = ttk.Label(frame_2, text="Text")
label_1.grid(row=0, column=0, sticky="S, W, N, E")
root.mainloop()
Expected result : there is a sunken frame inside another sunken frame. Inside the nested frame there is a label named "Text"
Actual result : The label is always in the upper left corner and does not want to move.
You can give cells on a grid a minimum size using the grid_columnconfigure() and grid_rowconfigure methods, as documented here.
Applied to your code (along with other corrections & improvements):
import tkinter as tk
from tkinter import ttk
root = tk.Tk()
root.title("Tk test")
root.geometry("800x800")
frame_1 = ttk.Frame(root, height=400, width=400, relief="sunken")
frame_1.grid(row=0, column=0)
frame_2 = ttk.Frame(frame_1, height=200, width=200, relief="sunken")
frame_2.grid(row=0, column=0, sticky="NSWE")
frame_2.grid_rowconfigure(0, minsize=200)
frame_2.grid_columnconfigure(0, minsize=200)
label_1 = ttk.Label(frame_2, text="Text")
label_1.grid(row=0, column=0, sticky="NW")
root.mainloop()
Since the grid manager doesn't know how many rows and columns there are to be on the main window, it doesn't allot the frames with the defined height and width.
If you add padding to each frame, you will see that the Text widget in not the upper left corner. But the Text widget will always be in the upper left corner as it has been placed on the 0th row and column.
Also, use rowconfigure and columnconfigure to ensure that the frames take the space specified by you on the main window.
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.
Hello everyone i am learning to make a gui with tkinter but i run into something and can't find the answer to it i have 3 frames a header a shadow for the header and a main content frame and that works fine
code :
root = Tk()
root.geometry("1080x600")
root.minsize(width=1080, height=600)
root.maxsize(width=1080, height=600)
root.title("learning ui")
headerFrame = Frame(root, height=50, bg="#17181b")
headerShadow = Frame(root, height=3, bg="#08090a")
contentFrame = Frame(root, bg="#17181b")
headerFrame.pack(side=TOP, fill=X)
headerShadow.pack(fill=X)
contentFrame.pack(fill=BOTH, expand=True)
root.mainloop()
Screen shot :
But when i pack something to the header it looses its height.
code:
root = Tk()
root.geometry("1080x600")
root.minsize(width=1080, height=600)
root.maxsize(width=1080, height=600)
root.title("learning ui")
headerFrame = Frame(root, height=50, bg="#17181b")
headerShadow = Frame(root, height=3, bg="#08090a")
contentFrame = Frame(root, bg="#17181b")
headerFrame.pack(side=TOP, fill=X)
headerShadow.pack(fill=X)
contentFrame.pack(fill=BOTH, expand=True)
main.e = Entry(headerFrame)
main.e.pack(side=RIGHT)
main.e.focus_set()
searchBtn = Button(headerFrame, text="Search", command=lambda: callback(retrieve_input()))
searchBtn.pack(side=RIGHT)
def callback(q):
print q
root.mainloop()
Screen shot:
All widgets are designed to "shrink to fit" their children. While this may seem counter-intuitive at first, it's the best way to do widget layout. Don't try to force a frame or window to be a specific size, just put the widgets in that you want and it will end up being the right size.
If you want to turn this feature off you can, but I strongly recommend against it. If you want to know more, search for "overrideredirect".