【问题标题】:Canvas within scroll frame滚动框架内的画布
【发布时间】:2018-01-16 00:35:32
【问题描述】:

我目前正在努力在滚动框架中使用 Tkinter 画布。滚动框架是指 Gonzo 在另一个线程 (Python Tkinter scrollbar for frame) 的答案中给出的 Frame-Canvas 结构。我已经适应了这个概念并添加了水平滚动条。现在,在内部框架的顶部,我想放置一个具有给定最小尺寸的画布。在这个最小尺寸小于内部框架(或整个窗口)的情况下,没有问题(因为不需要滚动)。但是,如果我将窗口(以及框架)的大小调整为小于画布的值(这是滚动条应该有用的条件),画布不会被拉伸到所需的大小(在下面的示例中,不是宽度= 500px),而是在框架的较小尺寸(宽度= 400px)处截断。滚动条处于活动状态,它们滚动仍为 500 像素的内部框架。

下面我给你一些关于代码和问题的更多细节。

感谢您对此进行调查。感谢您对这个问题的任何帮助,也许我只是在做一些明显错误的事情。

干杯, C.

ScrollFrame 类(存储在 scrollframe.py 中):

from Tkinter import *

class ScrollFrame(Frame):
    def __init__(self, parent, yscroll=True, xscroll=True, *args, **kw):
        Frame.__init__(self, parent, *args, **kw)
        self.canvas = Canvas(self, bd=0, highlightthickness=0)
        if xscroll:
            hscrollbar = Scrollbar(self, orient=HORIZONTAL)
            hscrollbar.pack(fill=X, side=BOTTOM, expand=FALSE)
            self.canvas.config(xscrollcommand=hscrollbar.set)
            hscrollbar.config(command=self.canvas.xview)
        if yscroll:
            vscrollbar = Scrollbar(self, orient=VERTICAL)
            vscrollbar.pack(fill=Y, side=RIGHT, expand=FALSE)
            self.canvas.config(yscrollcommand=vscrollbar.set)
            vscrollbar.config(command=self.canvas.yview)
        self.canvas.pack(side=LEFT, fill=BOTH, expand=TRUE)

        # reset the view
        self.canvas.xview_moveto(0)
        self.canvas.yview_moveto(0)

        # create a frame inside the canvas which will be scrolled with it
        self.interior = interior = Frame(self.canvas, bg="blue")
        self.interior_id = self.canvas.create_window(0, 0, window=interior, anchor=NW)

        # track changes to the canvas and frame width and sync them,
        # also updating the scrollbar
        def _configure_interior(event):
            # update the scrollbars to match the size of the inner frame
            size = (interior.winfo_reqwidth(), interior.winfo_reqheight())
            print "interior req: ",size,(interior.winfo_width(),interior.winfo_height())
            self.canvas.config(scrollregion="0 0 %s %s" % size)
            if interior.winfo_reqwidth() != self.canvas.winfo_width() or interior.winfo_reqheight() != sel    f.canvas.winfo_height():
                # update the canvas's width to fit the inner frame
                self.canvas.config(width=interior.winfo_reqwidth(), height=interior.winfo_reqheight(),)
        interior.bind('<Configure>', _configure_interior)

        def _configure_canvas(event):
            if interior.winfo_reqwidth() != self.canvas.winfo_width() or interior.winfo_reqheight() != sel    f.canvas.winfo_height():
                # update the inner frame's width to fill the canvas
                self.canvas.itemconfigure(self.interior_id, width=self.canvas.winfo_width(), height=self.c    anvas.winfo_height())
        self.canvas.bind('<Configure>', _configure_canvas)

主要代码: 从 Tkinter 导入 * 从滚动帧导入 *

root = Tk()
root.geometry("400x300")

frame = Frame(root, bg="blue")
frame.pack(expand=True, fill=BOTH)

sf = ScrollFrame(frame, bg="yellow")
sf.pack(expand=True, fill=BOTH)

sf.interior.config(width=500, height=400)
canvas = Canvas(sf.interior, width=500, height=400, bg="green")
canvas.pack(expand=True, fill=BOTH, side="top")

root.mainloop()

运行时是这样的: 1.canvas at top left corner (not yet scrolled) 2.canvas at bottom right corner (after scrolling)

问题:绿色画布应该是请求的大小 (500/400),但它似乎是滚动条附加到的祖母框架的大小 (400/300),而不是内部框架,这是一个滚动的 (500/400) 并且是画布的母框架。

【问题讨论】:

    标签: python tkinter tkinter-canvas


    【解决方案1】:

    _configure_canvas 方法是问题的根源。它将self.interior 框架的大小调整为self.canvas 的宽度,并且由于canvas 已包含选项expand=True, fill=BOTH,因此将其大小调整为400x300。

    另外,这个函数并不是获取滚动框所必须的,唯一需要的是每次调整self.interior的大小时调整self.canvas滚动区域的大小。

    这里是修改后的代码:

    from Tkinter import *
    
    class ScrollFrame(Frame):
        def __init__(self, parent, yscroll=True, xscroll=True, *args, **kw):
            Frame.__init__(self, parent, *args, **kw)
            self.canvas = Canvas(self, bd=0, highlightthickness=0)
            if xscroll:
                hscrollbar = Scrollbar(self, orient=HORIZONTAL)
                hscrollbar.pack(fill=X, side=BOTTOM, expand=FALSE)
                self.canvas.config(xscrollcommand=hscrollbar.set)
                hscrollbar.config(command=self.canvas.xview)
            if yscroll:
                vscrollbar = Scrollbar(self, orient=VERTICAL)
                vscrollbar.pack(fill=Y, side=RIGHT, expand=FALSE)
                self.canvas.config(yscrollcommand=vscrollbar.set)
                vscrollbar.config(command=self.canvas.yview)
            self.canvas.pack(side=LEFT, fill=BOTH, expand=TRUE)
    
            # reset the view
            self.canvas.xview_moveto(0)
            self.canvas.yview_moveto(0)
    
            # create a frame inside the canvas which will be scrolled with it
            self.interior = interior = Frame(self.canvas, bg="blue")
            self.interior_id = self.canvas.create_window(0, 0, window=interior, anchor=NW)
    
            # track changes to the frame width and update the scrollregion
            def _configure_interior(event):
                # update the scrollbars to match the size of the inner frame
                self.canvas.config(scrollregion=self.canvas.bbox('all'))
            interior.bind('<Configure>', _configure_interior)
    
    root = Tk()
    root.geometry("400x300")
    
    frame = Frame(root, bg="blue")
    frame.pack(expand=True, fill=BOTH)
    
    sf = ScrollFrame(frame, bg="yellow")
    sf.pack(expand=True, fill=BOTH)
    
    sf.interior.config(width=500, height=400)
    canvas = Canvas(sf.interior, width=500, height=400, bg="green")
    canvas.pack(expand=True, fill=BOTH, side="top")
    
    root.mainloop()
    

    【讨论】:

      猜你喜欢
      • 2021-09-28
      • 1970-01-01
      • 1970-01-01
      • 2015-04-18
      • 1970-01-01
      • 2016-06-06
      • 2018-07-13
      • 2017-01-18
      • 2011-06-23
      相关资源
      最近更新 更多