I want to create a listbox with an auto hiding scrollbar. I’ve been searching and found a class example; when I play around with it, the scrollbar doesn’t stayed attached to the right side as expected.
This is the code:
from tkinter import * class AutoScrollbar(Scrollbar): # a scrollbar that hides itself if it's not needed. only # works if you use the pack geometry manager. def set(self, lo, hi): if float(lo) <= 0.0 and float(hi) >= 1.0: self.pack_forget() else: if self.cget("orient") == HORIZONTAL: self.pack(fill=X) else: self.pack(fill=Y) Scrollbar.set(self, lo, hi) def grid(self, **kw): raise (TclError, "cannot use grid with this widget") def place(self, **kw): raise (TclError, "cannot use place with this widget") class Window1(Tk): def __init__(self): super().__init__() self.list_frame = Frame(self) self.list_frame.pack(fill=BOTH, expand=1) self.my_scrollbar = AutoScrollbar(self.list_frame, orient=VERTICAL) self.box1 = Listbox(self.list_frame, bg='black', fg='white', width=60, selectforeground='black', yscrollcommand=self.my_scrollbar.set, selectmode=EXTENDED) self.my_scrollbar.config(command=self.box1.yview) self.my_scrollbar.pack(side=RIGHT, fill=Y, pady=20) self.box1.pack(pady=20, fill=BOTH, expand=1) for num in range(15): self.box1.insert(END, num) if __name__ == '__main__': w = Window1() w.mainloop()
This is the first view when I run the code:
When I expand the window the scrollbar disappears properly:
But when I minimize the window, the scrollbar appears back but in an incorrect place and a strange shape:
Advertisement
Answer
It is because you didn’t specify side
option of pack()
inside AutoScrollbar.set()
, so it is TOP
by default. Also you forgot to specify side
in self.box1.pack(...)
.
Below is the modified code to fix the issues:
from tkinter import * class AutoScrollbar(Scrollbar): # a scrollbar that hides itself if it's not needed. only # works if you use the pack geometry manager. def set(self, lo, hi): if float(lo) <= 0.0 and float(hi) >= 1.0: self.pack_forget() else: if self.cget("orient") == HORIZONTAL: self.pack(fill=X, side=BOTTOM) # added side option else: self.pack(fill=Y, side=RIGHT) # added side option super().set(lo, hi) def grid(self, **kw): raise (TclError, "cannot use grid with this widget") def place(self, **kw): raise (TclError, "cannot use place with this widget") class Window1(Tk): def __init__(self): super().__init__() self.list_frame = Frame(self, pady=20) # added pady=20 self.list_frame.pack(fill=BOTH, expand=1) self.my_scrollbar = AutoScrollbar(self.list_frame, orient=VERTICAL) self.box1 = Listbox(self.list_frame, bg='black', fg='white', width=60, selectforeground='black', yscrollcommand=self.my_scrollbar.set, selectmode=EXTENDED) self.my_scrollbar.config(command=self.box1.yview) self.my_scrollbar.pack(side=RIGHT, fill=Y) # removed pady=20 self.box1.pack(fill=BOTH, expand=1, side=LEFT) # added side=LEFT and removed pady=20 for num in range(15): self.box1.insert(END, num) if __name__ == '__main__': w = Window1() w.mainloop()