Reputation: 513
I have a python script that creates a window displaying a grid of numbers with a vertical scrollbar. The problem I am having is that scrolling is jerky and not smooth. Is there any way of overcoming this? A test example is:
import tkinter as tk
class list_window(tk.Toplevel):
def __init__(self, title, *args, **kwargs):
tk.Toplevel.__init__(self, None, *args, **kwargs)
self.title(title)
self.geometry('1500x600')
self.outer_frame=tk.Frame(self)
canvas=tk.Canvas(self.outer_frame)
self.list_frame=tk.Frame(canvas)
scrollbar = tk.Scrollbar (self.outer_frame,orient="vertical",command=canvas.yview)
canvas.configure(yscrollcommand=scrollbar.set, yscrollincrement=10)
def scrollhelper(event):
canvas.configure(scrollregion=canvas.bbox("all"))
self.list_frame.bind("<Configure>",scrollhelper)
self.outer_frame.pack(side="top",fill="both",expand=1)
scrollbar.pack(side="right",fill="y")
canvas.pack(side="left",fill="both",expand=1)
canvas.create_window((0,0),window=self.list_frame,anchor='nw')
#Fill with a bunch of widgets, for example
import random
for i in range(1000):
for j in range(10):
tk.Label(self.list_frame, text=str(random.random())).grid(row=i, column=j)
def spawn_list_window():
win = list_window("My list window")
root = tk.Tk()
win = list_window("My List")
root.mainloop()
Upvotes: 0
Views: 318
Reputation: 1417
import tkinter as tk
from tkinter import ttk
class Treeview(ttk.Treeview):
def __init__(self, master, headings: list, col_widths: list = None, binds: dict = None):
super().__init__(master=master, columns=headings, show="headings")
self.col_widths = [] if col_widths is None else col_widths
self.scroll = ttk.Scrollbar(self)
self.configure(yscrollcommand=self.scroll.set)
self.scroll.configure(command=self.yview)
# Bind events to commands
if isinstance(binds, dict):
for k, v in binds.items():
try:
self.bind(f"<{k}>", v)
except tk.TclError:
self.bind(f"{k}", v)
self.reset()
self.scroll.pack(side=tk.RIGHT, fill=tk.Y)
# Append rows to the treeview
def populate(self, data, top_down=False):
for i, d in enumerate(data):
self.insert("", 0 if top_down else "end", values = d)
# Clears the entire tree
def clear(self):
self.delete(*self.get_children())
def reset(self):
for i, col in enumerate(self["columns"]):
self.heading(col, text=col)
if i < len(self.col_widths):
self.column(col, minwidth=self.col_widths[i], width=self.col_widths[i], stretch=tk.NO)
# Returns the first value which was selected
def one(self):
try:
item = self.item(self.selection()[0])["values"]
except IndexError: # Normally this happens if the item selected is the column header
return None
else:
return item
What you are trying can be more easily done using ttk.Treeview
. The above class is a wrapper around it which I use whenever I need one.
The below code is an example on using it.
root = tk.Tk()
tree = Treeview(root, [f"Heading {i+1}" for i in range(10)])
data = []
for i in range(1000):
data.append([])
for j in range(10):
data[-1].append(random.random())
tree.populate(data)
tree.pack(expand=True, fill=tk.BOTH)
root.mainloop()
Upvotes: 3