I have realised that the scrollbar in Tkinter is by default hidden unless and until you have put enough texts,buttons,etc on your frame to make the screen scrollable. Is there any way to show the scrollbar even when there's nothing present inside the frame?
The photo shown in the first link has the text "Sample scrolling label" only once whereas in the next link the text "Sample scrolling label" is shown 150 times and the scrollbar is now visible
Here is my code
from tkinter import *
root = Tk()
root.geometry("1366x768")
container = Frame(root)
canvas = Canvas(container)
scrollbar = Scrollbar(container,cursor="dot",width=30, orient="vertical",
command=canvas.yview,elementborderwidth=100)
scrollable_frame = Frame(canvas)
scrollable_frame.bind(
"<Configure>",
lambda e: canvas.configure(
scrollregion=canvas.bbox("all",10,10)
)
)
canvas.create_window((0,0),width=200, window=scrollable_frame)
canvas.configure(yscrollcommand=scrollbar.set)
for i in range(150):
Label(scrollable_frame, text="Sample scrolling label").pack()//This text appears on the frame 150
times
container.place(x=500,y=0,height=700,width=868)
canvas.pack(side=LEFT, fill=BOTH, expand=False)
scrollbar.pack(side="right", fill="y")
root.mainloop()
Is there any way to show the scrollbar even when there's nothing present inside the frame?
I assume you mean the presence of the thumb or slilder inside the scrollbar. The scrollbar as a whole will appear no matter what the contents.
The answer to your question is largely "no". The appearance of the thumb inside the scrollbar is controlled by the scrollbar. However, there might be some non-standard themes that make the thumb omnipresent. Hiding the thumb when there's nothing to scroll is pretty common though.
The one exception is the canvas. The scrollable region is completely under your control via the scrollregion attribute. Even in the case of the canvas, if the scrollable region is the same size (or smaller) than the window, the thumb won't appear.
The following example shows how to set the scrollable region to be twice the height of the canvas itself, and in this case the scrollbar thumb will show.
import tkinter as tk
root = tk.Tk()
canvas = tk.Canvas(root, width=400, height=400, background="bisque")
scrollbar = tk.Scrollbar(root, orient="vertical", command=canvas.yview)
canvas.configure(yscrollcommand=scrollbar.set)
canvas.pack(side="left", fill="both", expand=True)
scrollbar.pack(side="right", fill="y")
# set the scrollable area to 400x800
canvas.configure(scrollregion=(0, 0, 400, 800))
root.mainloop()
Related
I am writing a program in python in which I want the Text widget in tkinter to have a scrollbar .
this is a part of my code -
import tkinter as tk
import tkinter.font as tkfont
window = tk.Tk()
display_text = "START\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nEND"
font_1 = tkfont.Font(family='Helvetica', size=22, weight='bold')
my_label_1 = tk.Text(window, wrap=tk.WORD, bd=0, fg="white", bg="black", font=font_1, width=76, height=21,)
_scrollbar = tk.Scrollbar(window, command=my_label_1.yview)
my_label_1.configure(yscrollcommand=_scrollbar.set)
my_label_1.tag_configure("center", justify='center')
my_label_1.insert(1.0, display_text)
_scrollbar.pack(side=tk.RIGHT, ipadx=3, ipady=500, pady=(0, 48))
my_label_1.pack()
window.mainloop()
But I have 500 strings which I import from a csv file, when I put the strings in this code the strings go in disply_text variable, this works fine.
But for some of those strings the text widget is big enough and the scrollbar is not needed as the text widget is not scrollable for those. but the scrollbar still shows up it is disabled though but I don't want it to be there.
I know pack_forget() or grid_forget() can do this job, But Then what parameter should I put so I know that this iteration of text is not scrollable on the Text widget.
And my window is of fixed size i.e. window.resizable(False, False).
I have a question regarding placed buttons on a frame!
I created a canvas and placed a frame inside this canvas! Inside the canvas I place rectangles and oder stuff, drawn by tkinters canvas.create_rectangle, whereas I place certain widgets like buttons inside the frame. (Result: There are togehter in one window)
window_canvas = Canvas(root, borderwidth=0, background="grey", width = window_canvas_size[0], height = window_canvas_size[1], highlightthickness=0)
window_frame = Frame(window_canvas, background='white', borderwidth=0, width = canvas_size[0], height = canvas_size[1])
Now I made the window_canvas scrollable via:
def OnMousewheelConfigureProcessCanvas(self, event):
window_canvas.yview_scroll(int(-1*(event.delta/120)), "units")
window_canvas.bind("<MouseWheel>", m.OnMousewheelConfigureProcessCanvas)
The buttons are scrollable with the window_canvas, when I place the cursor outside of them, no problem.
However, when I hover with my mouse cursor above a button, the "scrollability" just doesn't work anymore. The window_canvas doesn't react to the mouse wheel this time.
I dont want to create a new window (via canvas.create_window) for every button. I have quite a few of them on screen, so I tried to keep it simple by placing one frame for all inside a canvas!
Looking forward to your solutions!
Thanks!
I created a tkinter app that shows a few matplotlib graph. Everything is working fine but the scrollbar is inactive until I resize the window. As soon as I manually resize the window it works like a charm...
Here is the pertinent code:
main_frame=tkinter.Frame(root)
main_frame.pack(fill=tkinter.BOTH, expand=1, pady=(4,0))
my_canvas =tkinter.Canvas(main_frame)
my_canvas.pack(side=tkinter.LEFT, fill=tkinter.BOTH, expand=1)
my_scrollbar=ttk.Scrollbar(main_frame, orient=tkinter.VERTICAL, command=my_canvas.yview)
my_scrollbar.pack(side=tkinter.RIGHT, fill=tkinter.Y)
my_canvas.configure(yscrollcommand=my_scrollbar.set)
my_canvas.bind('<Configure>', lambda e: my_canvas.configure(scrollregion=my_canvas.bbox("all")))
second_frame=tkinter.Frame(my_canvas)
my_canvas.create_window((0,0), window=second_frame, anchor="nw")
You need to configure the scrollregion of the canvas. You only do that from a binding on <Configure> which won't fire until the canvas resizes.
Add the following to your code after you call create_window and have added whatever widgets you're going to add in second_frame:
my_canvas.configure(scrollregion=my_canvas.bbox("all"))
I know this isn't the first time a question like this is asked, but even after like 2 hours of browsing the Internet I can't get it to work:
So I'm trying to create a Tkinter-Frame, that contains several Buttons (As Example I took 30). But Because I don't have enough space in my program, I need to add an Scrollbar next to it, so that one can scroll through the Buttons.
The Problems I had where, that the inner "moving part" of the bar was as big as the whole scrollbar and couldn't be moved, which I kinda solved by using scollregion=(0,0,1000,1000), but even then the moving of the bar had no effect on the canvas whatsoever.
Here Is the corresponding code that I extracted out of my program:
import Tkinter as tk
root = tk.Tk()
root.rowconfigure(0, weight=1)
root.columnconfigure(0, weight=50)
root.columnconfigure(1, weight=1)
root.minsize(300,400)
root.maxsize(300,400)
#Buttons
buttonFrame = tk.Canvas(root, bg='#bbb')
buttonFrame.grid(row=0, column=0, sticky=tk.N+tk.E+tk.S+tk.W)
buttonFrame.columnconfigure(0, weight=1)
scroll = tk.Scrollbar(root, command=buttonFrame.yview)
scroll.grid(row=0, column=1, sticky=tk.N+tk.E+tk.S+tk.W)
buttonFrame.configure(yscrollcommand=scroll.set)
for i in range(30):
tk.Button(buttonFrame, text=str(i+1)).grid(row=i, column=0, sticky=tk.N+tk.E+tk.S+tk.W)
root.mainloop()
As you (hopefully) see, the slider can't even be moved nor does it change anything on the canvas, even if I squeeze a scrollregion=(bla) somewhere in there.
2 Questions:
a.) What do I need to add (or remove), so that I can scroll through the list of Buttons
b.) Does the fix from a. still work when I make the Scrollbar a child of the buttonFrame instead of the root?
To add widgets to a Canvas you have to use the create_window method, not grid(). Then you have to update the canvas before setting the scrollregion.
for i in range(30):
btn = tk.Button(buttonFrame, text=str(i+1))
buttonFrame.create_window((100,i*50), window=btn)
root.update()
buttonFrame.config(scrollregion=buttonFrame.bbox("all"))
If you try that I suspect it's not what you were looking for, since the create_window method requires absolute positioning (you can't use grid or pack). That's why most people put a Frame in the Canvas, and add their widgets to that instead. Many people have abstracted this faux Frame that is actually a Frame in a Canvas in another Frame, including me.
I have a piece of tkinter code running on python 3.4 that is a large frame placed in a canvas with a vertical scrollbar, however the scrollbar is grayed out and doesn't seem to be linked to the size of the frame. The code I'm using is essentially:
class EntryWindow:
def __init__(self, master):
self.master = master
self.master.minsize(750, 800)
self.master.maxsize(1000, 800)
self.canvas = tk.Canvas(self.master, borderwidth=0, bg='#ffffff')
self.vsb = tk.Scrollbar(self.master)
self.master_frame = tk.Frame(self.canvas)
self.vsb.pack(side="right", fill='y')
self.canvas.pack(side='left', fill='both', expand=True)
self.canvas.create_window((0,0), window=self.master_frame, anchor='nw', tags='self.master_frame')
self.canvas.config(yscrollcommand=self.vsb.set)
self.master_frame.grid()
###build widgets and place into master_frame
...
The master_frame is filled with about 36 widgets placed using the grid geometry manager and reaches a vertical height of about 2000 pixels, but the scrollbar doesn't work.
I saw a post about using ttk scrollbar, but when I imported that I couldn't get it to work. The input statement I used was:
import tkinter as tk
import tkinter.ttk as ttk
and then replaced the line self.vsb = tk.Scrollbar(self.master) with self.vsb = ttk.Scrollbar(self.master) but that didn't fix it either. I also tried removing the min/max sizing on master (those aren't the final values, I've been playing with it).
Is there something I'm doing wrong? I feel like it might be in the line where I set the canvas.config() but I read the documentation and it seems to be right. Tomorrow I plan on trying to load the frame into the canvas after I've built the frame.
But in the meantime, and in case that doesn't work, any help would be great! Thanks!
You must do three things when configuring a scrolling canvas:
have the canvas notify the scrollbar when it scrolls, by configuring the yscrollcommand attribute of the canvas to point to the scrollbar
have the scrollbar control the canvas when it is dragged, by configuring the command attribute of the scrollbar
tell the canvas what part of the virtual canvas should be scrollable by configuring the scrollregion attribute of the canvas
You are neglecting to do #3. After adding the widgets to master_frame you should do this:
self.canvas.configure(scrollregion=self.canvas.bbox("all")
The above will tell the canvas and scrollbar that the area of the canvas that is scrollable is the area that encompasses all of the objects on the canvas.
Finally, you need to remove the following line of code, because you are already adding the frame to the canvas with create_window. Frames added to a canvas with pack, place or grid won't scroll:
# remove this line
self.master_frame.grid()
For a working example of a scrollable frame, see Adding a scrollbar to a group of widgets in Tkinter