Search code examples
pythontkinterbuttoncanvasscroll

How to add scrollable buttons in tkinter python


Currently, I'm using a tkinter canvas to try scroll buttons. I put twenty buttons on the canvas and none of them scrolled like I expected.

import tkinter as tk
from tkinter import *
from tkinter import ttk
from random import randint, choice

window = tk.Tk()
window.geometry('600x400')
window.title('Scrolling Buttons')

canvas = tk.Canvas(window, scrollregion = (0,0,2000,5000))

for i in range(20):
    Button(window, text = "Start", width = 10, bg = "#b5e2ff", activebackground = "#03c04a",     activeforeground = "white", font = ("Helevetica", 10)).pack()

canvas.pack(expand = True, fill = 'both')

canvas.bind('<MouseWheel>', lambda event: canvas.yview_scroll(-int(event.delta / 60), "units"))

scrollbar = ttk.Scrollbar(window, orient = 'vertical', command = canvas.yview)
canvas.configure(yscrollcommand = scrollbar.set)
scrollbar.place(relx = 1, rely = 0, relheight = 1, anchor = 'ne')

window.mainloop()

Solution

  • First of all, you have created those buttons as children of window, not canvas, so they will not be put inside the canvas.

    One of the way to achieve your goal is to create a frame inside the canvas and put those buttons inside that frame. Then put that frame inside the canvas using .create_window(...).

    Below is a simple example:

    import tkinter as tk
    
    window = tk.Tk()
    window.geometry('600x400')
    window.title('Scrolling Buttons')
    
    canvas = tk.Canvas(window)
    scrollbar = tk.Scrollbar(window, orient='vertical', command=canvas.yview)
    canvas.config(yscrollcommand=scrollbar.set)
    
    scrollbar.pack(side='right', fill='y')
    canvas.pack(side='left', fill='both', expand=1)
    
    # frame for those buttons
    frame = tk.Frame(canvas)
    canvas.create_window(0, 0, window=frame, anchor='nw', tags=('frame',))
    
    # set the width of the frame to the same as that of the canvas
    canvas.bind('<Configure>', lambda e: canvas.itemconfig('frame', width=e.width))
    
    # update canvas scrollregion whenever the frame is resized
    frame.bind('<Configure>', lambda e: canvas.config(scrollregion=canvas.bbox('all')))
    frame.bind('<MouseWheel>', lambda e: canvas.yview_scroll(-e.delta//60, 'units'))
    
    # add buttons to the frame
    for i in range(20):
        tk.Button(frame, text=f'Start {i+1}', width=10, bg='#b5e2ff',
                  activebackground='#03c04a', activeforeground='white',
                  font=('Helvetica', 10)).pack(pady=2)
    
    window.mainloop()
    

    Result:

    enter image description here