How to add a scrollbar to a widget
If you want to know everything about tkinker you can take a look at Effbot site.
The listbox widget can be very handy for a lot of purposes, expecially in Python that has this wonderful sintax for handling lists (that are the Python’s arrays). So, Learning to create listbox can take your scripts to the next level, making them so easy to use also for users different from the programmer and for the programmer too.
Scrollbars
To add a scrollbar to a listbox can be a little tricky at first, but it’s not so difficult, once you get it. For lists scrollbars are just necessary, if the items are not few as often happens. Once you created the two widget, the listbox and the scrollbars, you have to join them. You must use for the listbox the config method and pass to the yscrollcommand the set method of the scrollbar. For the scrollbar you must give the listbox.yview method as value of the argument command, always in the config method. Do not forget to pack the scrollbar to the RIGHT, to make it appear on the right of the listbox and use fill=Y.
Another stuff: the binding
Another important stuff is the binding of an action to the listbox. You can use the <Button-1> eventlistener or the <<ListBoxSelection>> eventlistener to attach some action when the user selects an item.
#listbox scrollbar from tkinter import * root = Tk() scrollbar = Scrollbar(root) scrollbar.pack(side=RIGHT, fill=Y) listbox = Listbox(root) listbox.pack() for i in range(100): listbox.insert(END, i) # attach listbox to scrollbar listbox.config(yscrollcommand=scrollbar.set) scrollbar.config(command=listbox.yview) root.mainloop()
In case you do not want to see the scrollbar, but still have the chance to scroll the items in the list you can avoid packing the scrollbar. It will be not visible on the screen, but it will be active when the mouse will be over the listbox.
#listbox scrollbar from tkinter import * root = Tk() scrollbar = Scrollbar(root) #scrollbar.pack(side=RIGHT, fill=Y) # Now it's active, but not visible listbox = Listbox(root) listbox.pack() for i in range(100): listbox.insert(END, i) # attach listbox to scrollbar listbox.config(yscrollcommand=scrollbar.set) listbox2 = Listbox(root) listbox2.pack(side="right") for i in range(100): listbox2.insert(END, i+100) listbox2.config(yscrollcommand=scrollbar.set) scrollbar.config(command=listbox.yview) root.mainloop()
Use the same scrollbar for 2 listbox
You can take as reference the same scrollbar widget for two different listbox. In this example I commented out the pack() method, so that the rulers fo the scrollbars are not visible. If you want them to be visible, uncomment that line
#scrollbar.pack(side=RIGHT, fill=Y)
Here is the whole code:
#listbox scrollbar from tkinter import * root = Tk() scrollbar = Scrollbar(root) #scrollbar.pack(side=RIGHT, fill=Y) listbox = Listbox(root) listbox.pack() for i in range(100): listbox.insert(END, i) # attach listbox to scrollbar listbox.config(yscrollcommand=scrollbar.set) listbox2 = Listbox(root) listbox2.pack() for i in range(100): listbox2.insert(END, i+100) listbox2.config(yscrollcommand=scrollbar.set) #scrollbar.config(command=listbox.yview) root.mainloop()
Scrolling 2 listboxes in sync
Someone asked me if it was possible to scroll two lisboxes in sync, so I made this code
#listbox scrollbar from tkinter import * root = Tk() def scrolllistbox2(event): listbox2.yview_scroll(int(-4*(event.delta/120)), "units") def scrolllistbox1(event): listbox1.yview_scroll(int(-4*(event.delta/120)), "units") scrollbar = Scrollbar(root) #scrollbar.pack(side=RIGHT, fill=Y) listbox1 = Listbox(root) listbox1.pack() for i in range(100): listbox1.insert(END, i) # attach listbox to scrollbar listbox1.config(yscrollcommand=scrollbar.set) listbox1.bind("<MouseWheel>", scrolllistbox2) listbox2 = Listbox(root) listbox2.pack() for i in range(100): listbox2.insert(END, i+100) listbox2.config(yscrollcommand=scrollbar.set) listbox2.bind("<MouseWheel>", scrolllistbox1) #scrollbar.config(command=listbox.yview) root.mainloop()
A possible case of real use of the sync listboxes scrolling
I thought at some cases in which it could be useful to scroll in sync two listboxes and I thought to this example.
P.S.: use the number 4 in the function to scroll the other listbox to make the 2 listboxes scroll the same number of lines each time, otherwise the listbox that the mouse is overing will scroll more lines and reach the bottom or the top faster.
#listbox scrollbar from random import randint from tkinter import * root = Tk() root.geometry("400x400") def scrolllistbox2(event): listbox2.yview_scroll(int(-4*(event.delta/120)), "units") def scrolllistbox1(event): listbox1.yview_scroll(int(-4*(event.delta/120)), "units") scrollbar = Scrollbar(root) scrollbar.pack(side=RIGHT, fill=Y) listbox1 = Listbox(root) listbox1.pack(expand=1, fill="both") for i in range(100): rnd = str(randint(1,100)) listbox1.insert(END, f"OUR INCOMES day {i}:" + rnd) # attach listbox to scrollbar listbox1.config(yscrollcommand=scrollbar.set) listbox1.bind("<MouseWheel>", scrolllistbox2) listbox2 = Listbox(root) listbox2.pack(expand=1, fill="both") for i in range(100): rnd = str(randint(1,100)) listbox2.insert(END, f"THEIR INCOMES day {i}: " + rnd) listbox2.config(yscrollcommand=scrollbar.set) listbox2.bind("<MouseWheel>", scrolllistbox1) #scrollbar.config(command=listbox.yview) root.mainloop()
Here is the window
Scrolling 2 listboxes in sync, side by side for better visual comparison
It would be even better to have them side by side, so that you can make a faster comparison with your referring data for the evaluation that we ipotized in the example above.
just put this on the pack method of both:
listbox1.pack(expand=1, fill="both", side="left")
for the first listbox
and…
listbox2.pack(expand=1, fill="both", side="left")
for the second one
The whole code would be this:
#listbox scrollbar from random import randint from tkinter import * root = Tk() root.title("2 Listbox scolling in sync") root.geometry("400x400") def scrolllistbox2(event): listbox2.yview_scroll(int(-4*(event.delta/120)), "units") def scrolllistbox1(event): listbox1.yview_scroll(int(-4*(event.delta/120)), "units") scrollbar = Scrollbar(root) scrollbar.pack(side=RIGHT, fill=Y) listbox1 = Listbox(root) listbox1.pack(expand=1, fill="both", side="left") for i in range(100): rnd = str(randint(1,100)) listbox1.insert(END, f"OUR INCOMES day {i}:" + rnd) # attach listbox to scrollbar listbox1.config(yscrollcommand=scrollbar.set) listbox1.bind("<MouseWheel>", scrolllistbox2) listbox2 = Listbox(root) listbox2.pack(expand=1, fill="both", side="left") for i in range(100): rnd = str(randint(1,100)) listbox2.insert(END, f"THEIR INCOMES day {i}: " + rnd) listbox2.config(yscrollcommand=scrollbar.set) listbox2.bind("<MouseWheel>", scrolllistbox1) #scrollbar.config(command=listbox.yview) root.mainloop()
The result is this:
Turn on and off the syncronizetion of the listboxes
In this code I added a button and a label to turn on and off the syncronization
#listbox scrollbar from random import randint from tkinter import * root = Tk() root.title("2 Listbox scolling in sync") root.geometry("400x400") switch = 1 def scrolllistbox2(event): global switch if switch==1: listbox2.yview_scroll(int(-4*(event.delta/120)), "units") def scrolllistbox1(event): global switch if switch == 1: listbox1.yview_scroll(int(-4*(event.delta/120)), "units") def do_switch(): global switch if switch: switch = 0 label['text'] = "Not in sync" else: switch = 1 label['text'] = "In sync" frame1 = Frame(root) frame1.pack(expand=1, fill="both") scrollbar = Scrollbar(frame1) scrollbar.pack(side=RIGHT, fill=Y) listbox1 = Listbox(frame1) listbox1.pack(expand=1, fill="both", side="left") for i in range(100): rnd = str(randint(1,100)) listbox1.insert(END, f"OUR INCOMES day {i}:" + rnd) # attach listbox to scrollbar listbox1.config(bg = "yellow", yscrollcommand=scrollbar.set) listbox1.bind("<MouseWheel>", scrolllistbox2) listbox2 = Listbox(frame1) listbox2.pack(expand=1, fill="both", side="left") for i in range(100): rnd = str(randint(1,100)) listbox2.insert(END, f"THEIR INCOMES day {i}: " + rnd) listbox2.config(bg="cyan",yscrollcommand=scrollbar.set) listbox2.bind("<MouseWheel>", scrolllistbox1) #scrollbar.config(command=listbox.yview) frame2 = Frame(root) frame2.pack() button = Button(frame2, text= "Sync/unsync", command=do_switch) button.pack() label = Label(frame2, text = "In sync") label.pack() root.mainloop()
I added two frame widget, one for the listboxes and another for the button and the label, for a better layout of the widgets. To the button there is attached a function that just makes 1 or 0 a boolean label called switch through the do_switch function. When its value is 0 each listbox scrolling does not activate the one of the other.
Using the scrollbars clicking and dragging the mouse on the bars
On scrollbar draggable for each list
Ok, we need to be able to drag the scrollbar with the right click of the mouse pressed. That is the code. I also added one scrollbar for each list. At this point they go in sync with the mousewheel, but if you drag the scrollbar with the mouse they will scroll indipendently.
The code to drag the bars is:
scrollbar1.config(command=listbox1.yview) scrollbar2.config(command=listbox2.yview)
The final version of the code. Some abstractions and some missing line of codes added.
#listbox scrollbar from random import randint import tkinter as tk root = tk.Tk() root.title("2 Listbox scolling in sync") root.geometry("400x400") switch = 1 def scrolllistbox(event, lb): global switch if switch==1: lb.yview_scroll(int(-4*(event.delta/120)), "units") print(event) def do_switch(): global switch if switch: switch = 0 label['text'] = "Not in sync" else: switch = 1 label['text'] = "In sync" def def_listbox(): scrollbar1 = tk.Scrollbar(frame1) scrollbar1.pack(side=tk.LEFT, fill=tk.Y) listbox1 = tk.Listbox(frame1) scrollbar1.config(command=listbox1.yview) listbox1.pack(expand=1, fill="both", side="left") for i in range(100): rnd = str(randint(1,100)) listbox1.insert(tk.END, f"INCOMES day {i}:" + rnd) listbox1.config(bg = "yellow", yscrollcommand=scrollbar1.set) return listbox1 # ====================== LISTBOXES ======================================= frame1 = tk.Frame(root) frame1.pack(expand=1, fill="both") listbox1 = def_listbox() listbox2 = def_listbox() listbox1.bind("<MouseWheel>", lambda event: scrolllistbox(event, listbox2)) listbox2.bind("<MouseWheel>", lambda event: scrolllistbox(event, listbox1)) # ================== SWITCH BUTTON ========================= frame2 = tk.Frame(root) frame2.pack() button = tk.Button(frame2, text= "Sync/unsync", command=do_switch) button.pack() label = tk.Label(frame2, text = "In sync") label.pack() # ========================================================== root.mainloop()
The video with an example
Another post like this (20/08/2019)
Scrolling bars into a text box in tkinter
This code adds a scrollbar to a Text widget in tkinter. Nothing different from attaching a scrollbar to a listbox, like we’ve seen above.
from tkinter import * root = Tk() scrollbar = Scrollbar(root) scrollbar.pack(side=RIGHT, fill=Y) textbox = Text(root) textbox.pack() for i in range(100): textbox.insert(END, f"This is an example line {i}\n") # attach textbox to scrollbar textbox.config(yscrollcommand=scrollbar.set) scrollbar.config(command=textbox.yview) root.mainloop()
Tkinter test for students
Tkinter articles
A little bit of restyling
#listbox scrollbar
from random import randint
import tkinter as tk
def scrolllistbox(event, lb):
global switch
if switch==1:
lb.yview_scroll(int(-4*(event.delta/120)), "units")
print(event)
def do_switch():
global switch
if switch:
switch = 0
label['text'] = "Not in sync"
else:
switch = 1
label['text'] = "In sync"
def create_data(listbox1):
for i in range(100):
rnd = str(randint(1,100))
listbox1.insert(tk.END, f"INCOMES day {i}:" + rnd)
def def_listbox():
scrollbar1 = tk.Scrollbar(frame1)
scrollbar1.pack(side=tk.LEFT, fill=tk.Y)
listbox1 = tk.Listbox(frame1)
scrollbar1.config(command=listbox1.yview)
create_data(listbox1)
listbox1.pack(expand=1, fill="both", side="left")
listbox1.config(bg = "yellow", yscrollcommand=scrollbar1.set)
return listbox1
def create_root():
"Returns the main windows"
root = tk.Tk()
root.title("2 Listbox scolling in sync")
root.geometry("400x400")
return root
def create_frames():
"Creates frames for widgets"
# listboxes frame
frame1 = tk.Frame(root)
frame1.pack(expand=1, fill="both")
# button and label frame
frame2 = tk.Frame(root)
frame2.pack()
return frame1, frame2
def create_widgets():
"Returns listboxes, button and label"
# listboxes
listbox1 = def_listbox()
listbox2 = def_listbox()
listbox1.bind("<MouseWheel>", lambda event: scrolllistbox(event, listbox2))
listbox2.bind("<MouseWheel>", lambda event: scrolllistbox(event, listbox1))
# ================== SWITCH BUTTON =========================
button = tk.Button(frame2, text= "Sync/unsync", command=do_switch)
button.pack()
label = tk.Label(frame2, text = "In sync")
label.pack()
# ==========================================================
pack = listbox1, listbox2, button, label
return pack
switch = 1
root = create_root()
frame1, frame2 = create_frames()
listbox1, listbox2, button, label = create_widgets()
root.mainloop()
Subscribe to the newsletter for updates
Tkinter templates
My youtube channel
Twitter: @pythonprogrammi - python_pygame