简体   繁体   中英

Tkinter Scrollable and expandable PanedWindow

I already searched a lot on Stackoverflow, and a lot of blogs, docs... And I don't find the way to make a "PanedWindow" to be scrollable AND expand + fill.

Check this example

"""Test"""
# pylint: disable=unused-wildcard-import,wildcard-import
from tkinter import Canvas, Scrollbar, Tk, Wm
from tkinter.constants import BOTH, CENTER, HORIZONTAL, LEFT, NSEW, X
from tkinter.ttk import Button, Frame, Label, PanedWindow, Style

STYLE = {
    "TButton": {
        "configure": {
            "background": "#333333",
            "foreground": "white",
            "padding": 8,
            "relief": "flat",
            "border": 2,
        },
        "map": {
            "background": [("active", "#777777")],
            "foreground": [("active", "white")],
        },
    },
}


class ScrollableFrame(Frame):
    def __init__(self, parent, *args, **kwargs):
        super().__init__(parent, *args, **kwargs)

        scrollbar = Scrollbar(self, orient="vertical")
        scrollbar.pack(side="right", fill="y")

        canvas = Canvas(self, borderwidth=2, background="red")
        canvas.pack(side=LEFT, fill=BOTH, expand=True)
        canvas.configure(yscrollcommand=scrollbar.set)

        scrollbar.configure(command=canvas.yview)
        frame = Frame(canvas, style="DEBUG.TFrame")

        canvas.create_window((0, 0), window=frame, anchor=CENTER)

        # COMMENT THIS, and the paned is scrollable, but frame does NOT expand
        # frame.pack(expand=1, fill=BOTH)

        frame.bind("<Configure>", self.on_configure)

        self.scollbar = scrollbar
        self.canvas = canvas
        self.frame = frame

    def on_configure(self, event):
        self.canvas.configure(
            scrollregion=self.canvas.bbox("all"),
        )


def create_right_pane(master):
    frame = Frame(master)
    label = Label(frame, text="This is a cool text")
    label.pack()
    return frame


def create_left_pane(master):
    frame = ScrollableFrame(master)
    title = Label(frame.frame, text="Hello !!!")
    title.pack(expand=True, fill=BOTH, anchor=CENTER)
    for i in range(100):
        Button(frame.frame, text=f"Channel {i} ❱").pack(expand=True, fill=BOTH)
    return frame


app = Tk(className="MyApp")
style = Style()
style.theme_create("app", None, STYLE)
style.theme_use("app")
app.title("MyApp")
app.geometry("1120x550")

splitpane = PanedWindow(app, orient=HORIZONTAL)
splitpane.pack(expand=True, fill=BOTH)

leftframe = create_left_pane(splitpane)
rightframe = create_right_pane(splitpane)

splitpane.add(leftframe, weight=1)
splitpane.add(rightframe, weight=5)

app.mainloop()

There is a comment in the ScrollableFrame class

  • comment the frame.pack() => it scrolls, but the content is not expanded and doesn't fill X 在此处输入图像描述

  • uncomment the frame.pack() => now the content fill the space, but it's not scrollable在此处输入图像描述

What I want to do is simply to make the content "fill the space" and to be "scrollable".

If you find the problem, and if you can fix it (or provide a solution)... thanks !

By default, the inner frame will expand or shrink to the optimal size for its contents. Since the contents of the frame aren't as wide as the canvas, the frame will not be as wide as the canvas.

If you want it to fill the canvas, you need to explicitly set the width to be the same as the width of the canvas whenever the canvas changes size.

First, let's make sure we can identify the inner frame by giving it a tag. You could just as easily capture the identifier returned by window_create .

canvas.create_window((0, 0), window=frame, anchor=CENTER, tags=("inner_frame",))

Next, add a binding to call a function whenever the canvas configuration changes.

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

Finally, define the resize function. On <Configure> events, the event object will contain a width parameter which represents the width of the object. We can use this to determine the width of the inner frame.

def resize_inner_frame(self, event):
    self.canvas.itemconfigure("inner_frame", width=event.width)

You might need to adjust the width to accommodate canvas borders.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM