0

I'm trying to make a GUI where I want several text widgets in a scrollable area, and that the width of the text widget should vary when the window size is changed. But I'm having trouble getting it to work. I think it has something to do with the create_window(), as I can make it work without the scroll function.

Example code below

import tkinter as tk


class Window:
    """Main window"""
    def __init__(self):
        """Initiate new gui window"""
        self.root = tk.Tk()
        self.root.minsize(800, 200)
        self.root.grid_columnconfigure(0, weight=1)

        background_grid = tk.Frame(master=self.root, bg="lightblue")
        background_grid.grid(row=0, column=0, sticky="ew")
        background_grid.grid_columnconfigure(0, weight=1)

        # Scroll area
        scroll = ScrollArea(background_grid, (0, 0))
        scroll.grid.configure(bg="darkgrey")
        scroll.canvas.grid_columnconfigure(0, weight=1)
        scroll.grid.grid_columnconfigure(0, weight=1)

        for i in range(0, 20):
            tk.Label(master=scroll.grid, text="Text").grid(row=i * 2, column=0, sticky="w")

            # Text box that I want to follow the size of the window
            text_box = tk.Text(master=scroll.grid, height=10)
            text_box.grid(row=i * 2 + 1, column=0, sticky="ew")
            text_box.grid_columnconfigure(0, weight=1)

            tk.Button(master=scroll.grid, text="Button").grid(row=i*2+1, column=1, sticky="e")

        scroll.update(self.root)


class ScrollArea:
    """Generate a scrollable area"""
    def __init__(self, master: tk.Frame or tk.Tk, coordinates: tuple, max_height=500, color="orange"):
        column, row = coordinates
        self.canvas = tk.Canvas(master=master, bg=color,
                                highlightcolor="grey", highlightbackground="grey", highlightthickness=1)
        self.canvas.grid(row=row, column=column, sticky="ew")

        self.grid = tk.Frame(master=self.canvas)
        self.grid.grid(row=0, column=0, sticky="ew")

        self.scrollbar = tk.Scrollbar(master=master, orient=tk.VERTICAL, command=self.canvas.yview)
        self.scrollbar.grid(row=row, column=column + 1, sticky="ns")

        self.canvas.configure(yscrollcommand=self.scrollbar.set)
        self.canvas.create_window((0, 0), window=self.grid)
        self.max_height = max_height

    def update(self, root_window: tk.Tk or tk.Toplevel):
        """Update the gui"""
        root_window.update_idletasks()

        # Set size of the grid to use for scroll region
        bbox = self.canvas.bbox(tk.ALL)
        display_width, display_height = self.grid.winfo_width(), min(self.max_height, self.grid.winfo_height())
        self.canvas.configure(scrollregion=bbox, width=display_width, height=display_height)
        self.grid.bind("<Enter>", self._bound_to_mousewheel)
        self.grid.bind("<Leave>", self._unbound_to_mousewheel)

        # Scroll to the top
        self.canvas.yview_moveto(0)

    def _bound_to_mousewheel(self, event):
        """Binds mouse wheel to scroll when the mouse is over the report area"""
        self.canvas.bind_all("<MouseWheel>", self._on_mousewheel)
        _ = event  # dummy

    def _unbound_to_mousewheel(self, event):
        """Removes the mouse wheel bind when the mouse leaves the report area"""
        self.canvas.unbind_all("<MouseWheel>")
        _ = event  # dummy

    def _on_mousewheel(self, event):
        """On scroll, move the canvas"""
        self.canvas.yview_scroll(int(-1 * (event.delta / 120)), "units")


def main():
    window = Window()

    window.root.mainloop()


if __name__ == '__main__':
    main()

1 Answer 1

1

You need to do two things: you need to set the width of the embedded window when the canvas changes size, and use the anchor option when creating the window.

class ScrollArea:
    def __init__(self, master: tk.Frame or tk.Tk, coordinates: tuple, 
        ...
        self.grid_id = self.canvas.create_window((0, 0), window=self.grid, anchor="nw")

        self.canvas.bind("<Configure>", self._resize_grid)

    def _resize_grid(self, event):
        self.canvas.itemconfigure(self.grid_id, width=event.width)
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.