【问题标题】:Tkinter Scrollable canvas create additional scroll area on topTkinter 可滚动画布在顶部创建额外的滚动区域
【发布时间】:2018-06-28 05:58:33
【问题描述】:

我对 python3 上的 Tkinter 很陌生,并试图在画布上制作一个可滚动框架。 我可以为默认窗口大小创建它,没有问题。但是当窗口最大化时,画布突然在顶部添加了额外的可滚动区域,我一直在寻找删除它/将可滚动框架保持在顶部的方法。

import tkinter as tk


class MainWindow(tk.Tk):

    def __init__(self, *args, **kwargs):
        super().__init__()
        self.geometry("1500x800")
        self.configure(background="#303030")


class Table(tk.Frame):

    def __init__(self, master, rows=2, columns=2):

        tk.Frame.__init__(self, master, background="#36363d")

        # Set table as list of rows
        self.table = []
        for row in range(rows):

            # Create list to store cell info in a rows
            current_row = []
            for column in range(columns):

                label = tk.Label(self, text="", borderwidth=0, width=columns, bg="#474756", )
                label.grid(row=row, column=column, sticky="nsew", padx=1, pady=1, )

                # Append cell (column) into rows
                current_row.append(label)

            # Append rows into whole table
            self.table.append(current_row)

        for column in range(columns):
            self.grid_columnconfigure(column, weight=1)


class ScrollablePage(tk.Frame):

    def __init__(self, master, *args, **kw):
        super().__init__(master)

        self.canvas = tk.Canvas(self, borderwidth=0, highlightthickness=0, bg="red")    # THIS TO EMPHASIZE THE CANVAS,

        self.frame = tk.Frame(self.canvas, *args, **kw)
        self.vsb = tk.Scrollbar(self, orient="vertical", command=self.canvas.yview)
        self.canvas.configure(yscrollcommand=self.vsb.set)

        self.vsb.pack(side="right", fill="y")
        self.canvas.pack(side="left", fill="both", expand=True)
        self.canvas_frame = self.canvas.create_window((0, 0), window=self.frame, anchor="nw", tags="self.frame")

        # Dynamic frame setup
        self.frame.bind("<Configure>", self.frame_conf)
        self.canvas.bind("<Configure>", self.frame_width)

        # Bind canvas to mousewheel
        self.canvas.bind("<Enter>", self.bound_to_mousewheel)
        self.canvas.bind("<Leave>", self.unbound_to_mousewheel)

    def frame_conf(self, event):
        """
        Reset the scroll region to encompass the inner frame
        """

        self.canvas.configure(scrollregion=self.canvas.bbox("all"))

    def frame_width(self, event):
        """
        Function to adjust canvas's frame upon expand (can't use pack)
        """

        self.canvas.itemconfig(self.canvas_frame, width=event.width)

    def mouse_wheel(self, event):
        """
        Capture mouse wheel changes to scroll page
        """
        self.canvas.yview_scroll(-1 * int(event.delta / 60), "units")

    def bound_to_mousewheel(self, event):
        self.canvas.bind_all("<MouseWheel>", self.mouse_wheel)

    def unbound_to_mousewheel(self, event):
        self.canvas.unbind_all("<MouseWheel>")


class PageTwo(ScrollablePage):

    def __init__(self, master):

        # Create page
        super().__init__(master, bg="#36363d")

        # EXAMPLE CONTENT
        controller = tk.Frame(self.frame, bg="#474756", width=0.9 * 1500, height=200, bd=0,)
        controller.pack(side="top", fill="x", padx=20, pady=10)

        self.table = Table(self.frame, rows=20, columns=10)
        self.table.pack(side="top", fill="both", padx=20, expand=1)


class MainContent(tk.Frame):

    # Setup main content's stacked-frame
    frames = {}

    # main_content_classes = [PageOne, PageTwo, PageThree, PageFour, PageFive, PageSix, PageDefault]  # << ORIGINAL ONE
    main_content_classes = [PageTwo]

    def __init__(self, master):

        # Create main content's frame
        super().__init__(master)

        # Place main content's frame in main window
        self.place(x=150, y=130, relwidth=0.9, relheight=0.83)

        # Create grid inside main content frame
        self.grid_rowconfigure(0, weight=1)
        self.grid_columnconfigure(0, weight=1)

        # Stacking pages in main content
        for FrameClass in MainContent.main_content_classes:
            page_name = FrameClass.__name__
            frame = FrameClass(self)
            frame.grid(row=0, column=0, sticky="nsew")
            MainContent.frames[page_name] = frame


class Datalab:

    def __init__(self, *args, **kwargs):

        main_window = MainWindow()
        MainContent(main_window)
        main_window.mainloop()

if __name__ == "__main__":
    app = Datalab()

我包含一些图片链接(不能直接发布)来说明

  • 默认窗口大小 - 顶部可滚动画布

  • 最大化窗口 - 画布在底部创建了额外的滚动区域(标记为红色:画布)

  • 最大化窗口 - 画布在顶部创建了额外的滚动区域(标记为红色:画布)

提前致谢

【问题讨论】:

  • 创建最小的工作示例,以便我们可以运行它作为查看问题。
  • 编辑问题并使用按钮 {} 正确格式化代码 - 目前您的缩进错误。
  • 如果框架比画布小,那么你必须看到框架下方的红色画布 - 或使用canvas.itemconfig(self.canvas_frame, height=event.height)自动更改框架的高度(类似于width)。
  • 请验证上面的代码sn-p是minimal reproducible example
  • @Nae 我已经更新了代码,请再次检查,谢谢

标签: python canvas tkinter scrollbar frame


【解决方案1】:

我遇到了同样的问题,发现vsb.get() 方法在所有内容都显示在窗口中时返回元组(0.0, 1.0)(最大化,或滚动区域内的项目不多)。不知道这个解决方案有多脏,但这对我有用。

鼠标滚轮只有在滚动条可滚动时才会生效:

def mouse_wheel(self, event):
    """
    Capture mouse wheel changes to scroll page
    """
    if self.vsb.get() != (0.0, 1.0):
        self.canvas.yview_scroll(-1 * int(event.delta / 60), "units")

【讨论】:

  • 哇……谢谢……你是怎么发现的……它有效!!我使用了额外的填充,但现在我不再需要它了:>
  • 我一直在寻找可滚动框架的良好实现,里面有很多小部件,而你的工作非常好。所以我很高兴我们互相帮助:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-12-18
  • 2012-08-01
  • 1970-01-01
  • 2023-03-06
  • 2021-12-01
  • 2018-05-02
  • 2022-12-05
相关资源
最近更新 更多