滚动条不起作用,滚动区域是否已正确设置?

时间:2019-06-22 23:33:25

标签: python-3.x tkinter scrollbar tkinter-canvas

对于my project,我正在尝试从this SO answer实施解决方案。但是当我运行我的应用程序时,即使滚动条溢出了它所在的框架,它也没有出现,

当我运行项目时,ScrollingCenterFrame2会超出窗口底部,并且调整大小不能解决问题。我在这里做什么错了?

以下是我的代码的最小可重现示例

from tkinter import *
from tkinter import ttk

class ScrollingCenterFrame2(ttk.Frame):
    #TODO: Implement this to replace the current SCF
    def __init__(self, parent):
        ttk.Frame.__init__(self, parent)

        cfTitle = ttk.Label(self, text="Mission Options")
        cfTitle.pack()

        self.app = app
        self.parent = parent

        # create canvas and scrollbar
        self.vsb = ttk.Scrollbar(self, orient=VERTICAL)
        self.vsb.pack(side=RIGHT, fill=Y)
        self.canvas = Canvas(self, highlightthickness=0, bg="#ededed", height=10, width=10)
        self.canvas.configure(yscrollcommand=self.vsb.set)
        self.canvas.pack(side=LEFT, fill=BOTH, expand=True)
        self.vsb.configure(command=self.canvas.yview)

        # add bindings for mousewheel
        self.canvas.bind("<Enter>", self._bind_mouse)
        self.canvas.bind("<Leave>", self._unbind_mouse)


        self.inner  = ttk.Frame(self.canvas)
        self.inner_id = self.canvas.create_window((4,4), window=self.inner, anchor=NW)

        self.inner.bind("<Configure>", self._configureInner)
        self.canvas.bind("<Configure>", self._configureCanvas)

    #end init


    def _bind_mouse(self, event=None):
        self.canvas.bind_all("<4>", self._on_mousewheel)
        self.canvas.bind_all("<5>", self._on_mousewheel)
        self.canvas.bind_all("<MouseWheel>", self._on_mousewheel)


    def _unbind_mouse(self, event=None):
        self.canvas.unbind_all("<4>")
        self.canvas.unbind_all("<5>")
        self.canvas.unbind_all("<MouseWheel>")


    def _on_mousewheel(self, event):
        """Linux uses event.num; Windows / Mac uses event.delta"""
        if event.num == 4 or event.delta > 0:
            self.canvas.yview_scroll(-1, "units")
        elif event.num == 5 or event.delta < 0:
            self.canvas.yview_scroll(1, "units")


    def _configureInner(self, event=None):
        #TODO: Fix the bug in here

        # update the scrollbars to match the size of the inner frame
        #size = (self.inner.winfo_width(), self.inner.winfo_height())
        #self.canvas.config(scrollregion="0 0 %s %s" % size)
        bbox = self.canvas.bbox("all")
        self.canvas.config(scrollregion=bbox)
        if self.inner.winfo_reqwidth() >= self.canvas.winfo_width():
            # update the canvas's width to fit the inner frame
            # only works before mainloop
            self.canvas.config(width=self.inner.winfo_reqwidth())
        screen_h = self.winfo_screenheight()
        height   = self.parent.winfo_rooty() + self.parent.winfo_height() - self.canvas.winfo_height() + self.inner.winfo_reqheight()
        if height < screen_h:
            self.canvas.configure(height=self.inner.winfo_reqheight())
    #end _configureInner


    def _configureCanvas(self, event=None):
        if self.inner.winfo_reqwidth() < self.canvas.winfo_width():
            self.canvas.itemconfigure(self.inner_id, width=self.canvas.winfo_width())
        elif self.inner.winfo_reqwidth() > self.canvas.winfo_width():
            self.canvas.config(width=self.inner.winfo_reqwidth())
    #end _configureCanvas

#end class ScrollingCenterFrame2


if __name__ == "__main__":
    app = Tk()
    f = ScrollingCenterFrame2(app)
    f.pack(expand=True, fill="both")

    for x in range(1,50):
        l = ttk.Label(f.inner, text=("Testing", x))
        l.pack(expand=True, fill=X)

    app.mainloop()

如您在此处看到的,对象数量被切断,并且调整大小不能解决滚动条问题

1 个答案:

答案 0 :(得分:0)

画布滚动的唯一方法是滚动区域大于屏幕的可视区域。您将滚动区域的值显式设置为与屏幕的可视部分相同的大小,因为您要强制将内部框架的高度与画布的高度相同。

您需要做的第一件事是删除更改内部框架高度的代码。该框架必须足够高以适合其内容,并且tkinter将自动执行此操作,而您无需执行任何操作。

因此,请删除以下代码行:

if (self.inner.winfo_reqheight() < self.canvas.winfo_height()) or (self.inner.winfo_height() < self.canvas.winfo_height()):
    self.canvas.itemconfigure(self.inner_id, height=self.canvas.winfo_height())

您需要做的第二件事是将滚动区域配置为足够大以包含画布上的所有内容。正常的方法是让画布告诉您屏幕上所有内容的边界框(带有self.canvas.bbox('all')),并将其用作scrollregion的值。

换句话说,替换为:

size = (self.inner.winfo_width(), self.inner.winfo_height())
self.canvas.config(scrollregion="0 0 %s %s" % size)

与此:

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