When I say a dynamic grid I'm saying a grid that adjusts the number of columns(like bootstrap) according to the window width, so it must adjust the "cards" accordingly, and when I say scrollable... well... easier to understand.
I've tried 2 aproachs:
- create a dynamic grid and then make it scrollable.
- create a scrollable grid and then make it dynamic.
I've failed in both ways! I've found out that for being scrollable the grid can't be in a simple frame, it must be in a Canvas. And for the canvas I'm having a hard time making it dynamic.
Down here is my dynamic grid code
class DynaGrid(tk.Frame):
def __init__(self, master=None, **kwargs):
tk.Frame.__init__(self, master, **kwargs)
self.columns = None
self.bind('<Configure>', self.re_grid)
def re_grid(self, event=None):
grid_width = self.winfo_width()
slaves = self.grid_slaves()
slaves_width = slaves[1].winfo_width()
cols = grid_width // slaves_width
if (cols == self.columns) | (cols == 0):
return
for i, slave in enumerate(reversed(slaves)):
slave.grid_forget()
slave.grid(row=i // cols, column=i % cols)
self.columns = cols
class CardFrame(tk.Frame):
def __init__(self, master=None, **kwargs):
tk.Frame.__init__(self, master, bd=1, relief=tk.RAISED, **kwargs)
tk.Label(self, text="Hello").pack()
def main():
root = tk.Tk()
frame = DynaGrid(root)
frame.pack(fill=tk.BOTH, expand=True)
CardFrame(frame).grid()
CardFrame(frame).grid()
CardFrame(frame).grid()
CardFrame(frame).grid()
CardFrame(frame).grid()
CardFrame(frame).grid()
CardFrame(frame).grid()
CardFrame(frame).grid()
root.mainloop()
if __name__ == '__main__':
main()
I wont waste other people's time posting my messy canvas code here instead I've got one from https://blog.tecladocode.com/tkinter-scrollable-frames/ which I've made the change to use my "cards" instead of labels.
import tkinter as tk
from tkinter import ttk
class ScrollableFrame(ttk.Frame):
def __init__(self, container, *args, **kwargs):
super().__init__(container, *args, **kwargs)
canvas = tk.Canvas(self)
scrollbar = ttk.Scrollbar(self, orient="vertical", command=canvas.yview)
self.scrollable_frame = ttk.Frame(canvas)
self.scrollable_frame.bind(
"<Configure>",
lambda e: canvas.configure(
scrollregion=canvas.bbox("all")
)
)
canvas.create_window((0, 0), window=self.scrollable_frame, anchor="nw")
canvas.configure(yscrollcommand=scrollbar.set)
canvas.pack(side="left", fill="both", expand=True)
scrollbar.pack(side="right", fill="y")
class TestFrame(tk.Frame):
def __init__(self, master=None, **kwargs):
tk.Frame.__init__(self, master, bd=5, relief=tk.RAISED, **kwargs)
tk.Label(self, text="name").pack(pady=10)
root = tk.Tk()
frame = ScrollableFrame(root)
for i in range(50):
TestFrame(frame.scrollable_frame).grid()
frame.pack()
root.mainloop()
To make the dynamic scrollable canvas the tricky part here is use the re_grid function inside the canvas. I'm lost in how I'll get the window width correctly like I did in the dynaGrid code.
In the end I want a mash up of these two codes; a Class that is some sort of frame with dynamic grid with lateral scroll.