8

My aim is to have a scrollbar that stays at the right-side of a full-screen window, allowing the user to scroll up and down through various different widgets (such as labels & buttons). From other answers I've seen on this site, I've come to the conclusion that a scrollbar has to be assigned to a canvas in order for it to function properly, which I have tried to include in my code but have not had much success with.

The below code shows a simplified version of what I've managed to accomplish so far:

from tkinter import *
root = Tk()
root.state("zoomed")
root.title("Vertical Scrollbar")
frame = Frame(root)
canvas = Canvas(frame)
Label(canvas, text = "Test text 1\nTest text 2\nTest text 3\nTest text 4\nTest text 5\nTest text 6\nTest text 7\nTest text 8\nTest text 9", font = "-size 100").pack()
scrollbar = Scrollbar(frame)
scrollbar.pack(side = RIGHT, fill = Y)
canvas.configure(yscrollcommand = scrollbar.set)
canvas.pack()
frame.pack()
root.mainloop()

I'm facing two issues when running this code:

One is that the scrollbar is inactive, and doesn't allow for the user to scroll down to view the rest of the text.

The other is that the scrollbar is attached to the right-side of the text, rather than the right-side of the window.

So far, none of the other answers I've found on this site have enabled me to amend my code to support a fully-functioning scrollbar for my program. I'd be very grateful for any help anyone reading this could provide.

Luke25361
  • 155
  • 2
  • 3
  • 9
  • You have to use `create_window` rather than `pack` to put the frame in the canvas. See http://stackoverflow.com/a/3092341/7432 – Bryan Oakley Nov 10 '16 at 12:29
  • @bryan-oakley Hi Bryan, thanks for the reply. I've tried replacing '.pack()' with '.create_window((4, 4), window = frame, anchor = "nw")' as the link you've provided demonstrated. Unfortunately, this results in my text label disappearing completely, with only a scrollbar being displayed. Also, should I be placing my frame inside a canvas, rather than a canvas inside my frame? – Luke25361 Nov 10 '16 at 13:38
  • the label needs to be inside the frame, the frame needs to be added to the canvas with `create_window`. – Bryan Oakley Nov 10 '16 at 13:49
  • @bryan-oakley Ok, I've changed `frame.pack()` to `frame.create_window((4, 4), window = canvas, anchor = "nw")` and I've changed `canvas.create_window((4, 4), window = frame, anchor = "nw")` back to `canvas.pack()`. This is giving me the following error: `AttributeError: 'Frame' object has no attribute 'create_window'`. – Luke25361 Nov 10 '16 at 13:54
  • 1
    if you want to scroll frame then put frame inside canvas (`canvas.create_window(..., frame)`). if you want to scroll label then put label inside canvas (`canvas.create_window(..., label)`) or label inside frame (`Label(frame)`) and frame inside canvas (`canvas.create_window(..., frame)`). See Bryan link how to add frame to canvas (and have frame with scrollbar) and then you can easily add all widgets in this frame. – furas Nov 11 '16 at 00:03

2 Answers2

12

See again link: https://stackoverflow.com/a/3092341/7432

It shows how to create scrolled frame - and then you can add all widgets in this frame.

import tkinter as tk


def on_configure(event):
    # update scrollregion after starting 'mainloop'
    # when all widgets are in canvas
    canvas.configure(scrollregion=canvas.bbox('all'))


root = tk.Tk()

# --- create canvas with scrollbar ---

canvas = tk.Canvas(root)
canvas.pack(side=tk.LEFT)

scrollbar = tk.Scrollbar(root, command=canvas.yview)
scrollbar.pack(side=tk.LEFT, fill='y')

canvas.configure(yscrollcommand = scrollbar.set)

# update scrollregion after starting 'mainloop'
# when all widgets are in canvas
canvas.bind('<Configure>', on_configure)

# --- put frame in canvas ---

frame = tk.Frame(canvas)
canvas.create_window((0,0), window=frame, anchor='nw')

# --- add widgets in frame ---

l = tk.Label(frame, text="Hello", font="-size 50")
l.pack()

l = tk.Label(frame, text="World", font="-size 50")
l.pack()

l = tk.Label(frame, text="Test text 1\nTest text 2\nTest text 3\nTest text 4\nTest text 5\nTest text 6\nTest text 7\nTest text 8\nTest text 9", font="-size 20")
l.pack()

# --- start program ---

root.mainloop()
Community
  • 1
  • 1
furas
  • 134,197
  • 12
  • 106
  • 148
3

I would recommend using tkScrolledFrame https://pypi.org/project/tkScrolledFrame/ They have a great little example on the website too. So easy to use and works great for me.

Below is a quick example:


from tkscrolledframe import ScrolledFrame
import tkinter as tk

# Create a root window
root = tk.Tk()

frame_top = tk.Frame(root, width=400, height=250)
frame_top.pack(side="top", expand=1, fill="both")

# Create a ScrolledFrame widget
sf = ScrolledFrame(frame_top, width=380, height=240)
sf.pack(side="top", expand=1, fill="both")

# Bind the arrow keys and scroll wheel
sf.bind_arrow_keys(frame_top)
sf.bind_scroll_wheel(frame_top)

frame = sf.display_widget(tk.Frame)

l = tk.Label(frame, text="Test text 1\nTest text 2\nTest text 3\nTest text 4\nTest text 5\nTest text 6\nTest text 7\nTest text 8\nTest text 9", font="-size 20")
l.pack()

root.mainloop()
KazO
  • 41
  • 3
  • 1
    Please explain how the link relates to the question and how it works. – M-Chen-3 Dec 09 '20 at 16:48
  • I'll be honest, it's been a very long time since I've looked at this code, but I think what you've found would've been exactly what I was looking for! Hope this answer helps others – Luke25361 Dec 09 '20 at 20:19
  • 1
    Okay, I added an example :) – KazO Dec 20 '20 at 19:00
  • Unfortunately it seems to be dead but then again so is Tkinter :P Thanks for the answer! (I made a non-archived version of the repo at https://github.com/thetechrobo/tkScrolledFrame) – TheTechRobo the Nerd Jun 30 '21 at 15:30