Scrollable Tkinter GUI with shiftable pods

Viewed 21

I am trying to make a GUI such as this with pods, each containing their own elements such as text, images and buttons. enter image description here

My goal is to make it so that the so called pods can be added to the GUI window (a scrolling capable window) at any point in the code and updated in the window shifting the previous pod to the right or down to the next row if the current row is full like the image below.enter image description here I have never messed with Tkinter before so I was wondering if anyone could help me with what steps I would need to take to make such a GUI.

1 Answers

Implement a class that inherits from the Frame class. You can then create as many instances of this class that you want. Since you want the pods to wrap, you can use a Text widget to hold the pods since it's the only scrollable widget that natively supports wrapping.

The "pod" class might look something like this:

class Pod(tk.Frame):
    def __init__(self, parent, title, subtitle, image):
        super().__init__(parent, bd=2, relief="groove")

        if isinstance(image, tk.PhotoImage):
            self.image = image
        else:
            self.image = tk.PhotoImage(file=image_path)

        self.title = tk.Label(self, text=title)
        self.image_label = tk.Label(self, image=self.image, bd=1, relief="solid")
        self.subtitle = tk.Label(self, text=subtitle)
        self.b1 = tk.Button(self, text="Button 1")
        self.b2 = tk.Button(self, text="Button 2")

        self.grid_rowconfigure(1, weight=1)
        self.grid_columnconfigure((0,1), weight=1)

        self.title.grid(row=0, column=0, columnspan=2, sticky="ew")
        self.image_label.grid(row=1, column=0, columnspan=2, sticky="nsew", padx=8, pady=8)
        self.subtitle.grid(row=2, column=0, columnspan=2, sticky="ew")
        self.b1.grid(row=3, column=0)
        self.b2.grid(row=3, column=1)

You can create another class to manage these objects. If you base it on a Text widget you get the wrapping behavior for free. Though, you could also base it on a Frame or Canvas and manage the wrapping yourself.

It might look something like this:

class PodManager(tk.Text):
    def __init__(self, parent, **kwargs):
        super().__init__(parent, **kwargs)
        self.configure(state="disabled", wrap="char")
        self.pods = []

    def add(self, pod):
        self.pods.append(pod)
        self.configure(state="normal")
        self.window_create("end", window=pod)
        self.configure(state="disabled")

To tie it all together, create one PodManager class, then pass one or more instances of Pod to its add method:

import tkinter as tk
...
root = tk.Tk()
pm = PodManager(root)
vsb = tk.Scrollbar(root, orient="vertical", command=pm.yview)
pm.configure(yscrollcommand=vsb.set)
vsb.pack(side="right", fill="y")
pm.pack(side="left", fill="both", expand=True)

for i in range(10):
    image = tk.PhotoImage(width=200,height=100)
    pod = Pod(pm, f"Title #{i+1}", "More Text", image)
    pm.add(pod)
root.mainloop()

screenshot of small window with active scrollbar screenshot of larger window that shows wrapping

Related