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
Related
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 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()
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.
Is there a way to use tkinter's Tk() frame with a canvas in a way that it covers the entire screen but doesnt get bigger than the screen.
I mean it shall be similar to fullscreen.
If this is a part of my code:
class X:
def __init__(self):
self.tk = Tk()
self.canvas = Canvas(self.tk, width=500, height=500, highlightthickness=0)
self.canvas.pack()
How would I achieve this? I think it is something with:
self.canvas.attributes(width=x)
Also: How would I now how big the canvas currently is (considering I don't save it in a variable)? Is there some kind of method or attribute of Canvas I could access?
edit the self.canvas.pack() to self.canvas.pack(fill='both', expand=True)
then the canvas will fill the entire window.
I have a fairly large size GUI built in tkinter using the grid manager method. I need to add a scrollbar to the entire window and Im having some trouble. Here is a very crude version of a scroll-bar using the grid manager in Tkinter (i dont want to scroll the list box, i want to scroll the entire Tk window).
import Tkinter
from Tkinter import *
Tk = Tkinter.Tk
self=Tk()
listbox = Listbox(self, width = 10, height = 60)
listbox.grid(row =0, column=0)
scrollbar = Scrollbar(self)
scrollbar.grid(sticky=E, row = 0, rowspan = 100, column = 11, ipady = 1000)
mainloop()
Is it possible to fix the Tkinter window size (using grid manager) and add a scrollbar which then allows the user to view additional content? The window is too large and additional content needs to be viewed so the only option i see is a scrollbar. I only see examples using the pack method. As you can probably guess I am new to Tkinter and would appreciate any input.
Thanks to all in advance.
You cannot scroll the entire contents of a root window, a Toplevel window, or a Frame. The solution is to put all of your widgets in a canvas, and then add a scrollbar to the canvas. There are questions on this site that give examples, such as Python Tkinter scrollbar for frame