Python Tkinter 问题:画布中的框架

0 投票
1 回答
4516 浏览
提问于 2025-04-17 04:26

我正在尝试设置一个可以滚动的框架系列,所以我把它们放在一个画布(Canvas)里。下面我附上了一些示例代码,展示了我遇到的问题。

不过,我有三个问题:

  1. 框架 c 似乎没有横向扩展到填满整个画布。
  2. 如果我使用多个框架 c,画布可以滚动,但如果我尝试把我的 FrameRow 放到一个单独的框架 c 里,画布就不再滚动了。
  3. 使用多个框架 c 时,最后一个 FrameRow 被截断了。

按钮“左”和“右”展示了当这些按钮不放在画布里的时候我得到的效果。

我更希望使用单个框架 c,并把所有的 FrameRows 放在里面,但我需要滚动功能正常工作。

import * from Tkinter
import FrameRow
root = Tk()
root.title("Testing")

containerFrame =  Frame(root)
containerFrame.config(bg="red")
containerFrame.pack(side=TOP, fill=BOTH, expand=1)

# Frame showing proper behavior
a = Frame(containerFrame, bg="black")
a.pack(side=TOP, fill=X, expand=0)

btnLeft = Button(a)
btnLeft.config(text="LEFT")
btnLeft.pack(side=LEFT, fill=X, expand=1)

btnRight = Button(a)
btnRight.config(text="RIGHT")
btnRight.pack(side=RIGHT, fill=X, expand=0)


# Canvas
canvas = Canvas(containerFrame)
scrollbar = Scrollbar(containerFrame, orient=VERTICAL)

scrollbar.config(command=canvas.yview)
canvas.config(bg="blue", yscrollcommand=scrollbar.set)
scrollbar.pack(side=RIGHT, fill=Y)
canvas.pack(side=LEFT, fill=BOTH, expand=1)

# Multiple Frames within Canvas    
frameRow = range(30)
c = range(30)
for r in xrange(0,30):
    c[r] = Frame(canvas)
    c[r].config(bg="green")

    frameRow[r] = FrameRow.FrameRow()
    frameRow[r].setFrame(c[r])
    frameRow[r].setRow(r)
    frameRow[r].createRow()

    c[r].pack(side=TOP, fill=X, expand=1)
    canvas.create_window(0, (r+1)*30, window=c[r], anchor="nw")

canvas.config(scrollregion = canvas.bbox(ALL))

# OR
# Single Frame within Canvas
##c = Frame(canvas)
##c.config(bg="green")
##
##frameRow = range(30)
##for r in xrange(0,30):
##    frameRow[r] = FrameRow.FrameRow()
##    frameRow[r].setFrame(c)
##    frameRow[r].setRow(r)
##    frameRow[r].createRow()
##
##c.pack(side=TOP, fill=X, expand=1)
##canvas.create_window(0, 0, window=c, anchor="nw")

root.mainloop()

FrameRow 类是这样定义的:

from Tkinter import *

class FrameRow():
    _frame = "Default"
    _row = 0

    def setFrame(self, frame):
        self._frame = frame

    def setRow(self, row):
        self._row = row

    def createRow(self):
        self.frameRow = Frame(self._frame)
        self.frameRow.config(bg="yellow")
        self.frameRow.pack(side=TOP, fill=X, expand=1)

        self.btn1 = Button(self.frameRow)
        self.btn1.config(text="Button "+str(self._row)+"A")
        self.btn1.pack(side=LEFT, fill=X, expand=1)

        self.btn2 = Button(self.frameRow)
        self.btn2.config(text="Button "+str(self._row)+"B")
        self.btn2.pack(side=RIGHT, anchor=E, fill=X, expand=0)

我是不是漏掉了什么,让框架 c 扩展到画布的宽度?

我在滚动和单个框架 c 的使用上是不是做错了什么?

有没有什么好的教程或示例,能告诉我该怎么做?

谢谢!

1 个回答

1

看起来你在一个画布里放置窗口,同时又创建了一个窗口对象。老实说,我从来没有这样做过,但我觉得这样放置可能没什么用。

当你在画布中创建一个小部件(也就是一个对象)时,它是不会自动扩展到填满整个画布的。你需要做的是绑定一个<Configure>事件到画布上。这个事件会在画布大小变化时(还有其他一些情况下)触发。然后你可以调整每个框架的大小,使其适应画布的宽度。

既然你说你更喜欢使用一个单独的框架,把其他行放在里面,这可能是最简单的解决方案。但再次强调,这个单独的框架不会自动变大或变小来适应画布,你需要通过<Configure>绑定来实现这一点。

确保在使用create_window将框架添加到画布后,配置画布的滚动区域。看起来你在注释掉的代码中忘记了这一点,这肯定会导致画布无法滚动。

撰写回答