I want to display a table (variable number of rows) with tkinter where:
This post (Adding a scrollbar to a group of widgets in Tkinter) is helpful to understand scrolling with tkinter...but doesn't fulfill with all requirements above.
The main tricks are:
Here a solution example:
# Standard libraries
import tkinter as tk
class ResultWindow(tk.Tk):
def __init__(self):
# Initialize the GUI
super().__init__()
# Create the main widgets
self.canvas = tk.Canvas(self)
self.vsb = tk.Scrollbar(self, orient="vertical", width=25)
self.frame = tk.Frame(self.canvas)
# Add them to the toplevel layout
self.canvas.pack(side="left", fill="y")
self.vsb.pack(side="right", fill="y")
self.canvas.create_window((0, 0), window=self.frame, anchor="nw")
# Bind events to the widgets
self.canvas.bind_all("<MouseWheel>", self.on_mousewheel)
self.vsb.bind("<MouseWheel>", lambda event: "break")
self.frame.bind("<Configure>", self.on_frame_configure)
# Link Canvas scroll with Scrollbar
self.canvas.configure(yscrollcommand=self.vsb.set)
self.vsb.configure(command=self.canvas.yview)
# Add the frame to define the way
self.l_cell = None
# Add arbitrary content (to create our table)
self.add_content(200, 5)
def add_content(self, rows, cols):
# Declare functions to manage code labels highlighting
set_color = lambda event: event.widget.config(bg="grey")
reset_color = lambda event: event.widget.config(bg="SystemButtonFace")
for col in range(cols):
for row in range(rows):
# Add the cells to the grid
text = f"row: {row}, col: {col}"
self.l_cell = tk.Label(self.frame, text=text, relief="solid")
self.l_cell.grid(row=row, column=col, sticky="nsew")
# Bind each cell to events
self.l_cell.bind("<Enter>", set_color)
self.l_cell.bind("<Leave>", reset_color)
self.l_cell.bind("<Button-3>", self.on_click)
def on_frame_configure(self, event):
# Resize the canvas to fit with the content
self.canvas.config(width=self.canvas.bbox("all")[2],
height=self.canvas.bbox("all")[3])
# Adjust the scrollable scope to the new size of the canvas
self.canvas.configure(scrollregion=self.canvas.bbox("all"))
def on_mousewheel(self, event):
# Update the scroll according to the mousewheel scroll size
self.canvas.yview_scroll(int(-1 * (event.delta / 120)), "units")
def on_click(self, event):
# Clear the clipboard
self.clipboard_clear()
# Get the Label widget code and add it to the clipboard
self.clipboard_append(event.widget.cget("text"))
app = ResultWindow()
app.mainloop()