Python Tkinter画布在使用网格布局时形状不显示,但在使用打包时显示?

1 投票
1 回答
824 浏览
提问于 2025-04-18 14:11

这是我第一次在stackexchange发帖。我从一个月前开始自学编程,进展得比较慢。遇到了很多问题,因为我都是随便找网上的教程,根本没看过书,完全靠自己的经验,试着去做一些“项目”(即使是简单的项目也花了我很多时间)。

总之,我遇到了很多问题,最终都解决了,虽然花了不少时间。有些问题我只是绕过了,虽然不知道哪里出错了,但我知道那个地方肯定有问题。

说了这么多,我决定如果遇到解决不了的问题,就来这里问问。所以我有一个简单的问题,搞不太明白:

from Tkinter import *

root = Tk()
backgroundCanvas = Canvas(root)
backgroundCanvas.grid(row = 0, column = 0, sticky = N+S+E+W)
#backgroundCanvas.pack(fill = BOTH, expand = True)

margin= 20
padding = 10
cellWidth = 100
cellHeight = 130

xypos = [ ]
xdif = cellWidth + 2*padding
ydif = cellHeight + 2*padding
for i in range(4):
    for j in range(4):
        a = margin+padding+i*xdif
        b = margin+j*ydif
        xypos.append((a,b,a+cellWidth,b+cellHeight))
for xpos1,ypos1,xpos2,ypos2 in xypos:
    backgroundCanvas.create_rectangle((xpos1,ypos1),(xpos2,ypos2), fill = "blue")
    print xpos1,ypos1,xpos2,ypos2

root.mainloop()

抱歉没有附上图片,但如果我用网格布局,它只会在“第一行”创建3个完整的矩形,然后在“第二行”创建3个半切的矩形(不是行网格,行网格只有一个块,行0,列0)。但是如果我用打包布局,它就能正常显示,显示所有16个矩形。

谢谢你们花时间看这个,我知道有点不清楚!

补充一下:还有另一个问题(我知道应该在另一个帖子问,但这个问题规模小一点),假设我有四个画布,它们的父级都是根节点。它们的名字如下:

firstCanvas = Canvas(root)
secondCanvas = Canvas(root)
thirdCanvas = Canvas(root)
fourthCanvas = Canvas(root)

假设我已经把它们都打包或用网格布局了。现在我想把鼠标点击事件绑定到每一个画布上。我这样做:

firstCanvas.bind("", mousePressed) fourthCanvas.bind("", mousePressed)

等等……但是如果我有10个画布,我是不是得手动复制那行代码10次?我能不能创建一个循环,把它们都整齐地绑定上?问题是我不能用类似number+Canvas.bind...这样的方式,因为这样不行。很多东西都是未定义的,更别提根本就不工作了。

用字符串来解决这个问题也不行,因为firstCanvas不是字符串,它实际上是一个指向画布的“变量”。

我曾经做过的一个变通方法是创建一个字典,里面用的确实是可以作为变量的字符串。例如,对于number in [first,...],canvas_data["%d" %(number) +Canvas] = do_your_thing_here,这样可以,但不太优雅。

更不用说我还不确定在tkinter中用字典变量来指向实际的画布是否有效(还没试过)。如果可以的话,我可以这样做……比如canvas_data[firstCanvas].bind("", mousePressed)。

但这不是重点,我想找另一种方法,是否有办法“改变”那些不是字符串的字符?

换句话说,我有一些变量叫variableA、variableB、variableC,我想做类似这样的事情(两个例子):

    for letter in [A,B,C]:
        variable+letter = letter

    varA = 1, varB = 2, varC = 3
    for letter in [A,B,C]: 
        print var+letter.

希望我说得够清楚……任何帮助都非常感谢。

1 个回答

1

在名字 firstCanvassecondCanvas 的地方,使用列表和数字。

canvases = []

for x in range(10):
    canvases.append( Canvas(root) )

这样你可以创建任意数量的画布,然后你可以像这样使用它们。

canvases[0]
canvases[1]
etc.

同样,你也可以对所有画布进行绑定。

for c in canvases:
    c.bind(...)

或者你可以一次性做到这一点。

canvases = []

for x in range(10):
    c = Canvas(root)
    c.bind(...)
    canvases.append( c )

variableAvariableBvariableC 的地方,使用字典。

variables = {}

for letter in 'ABC':
    variables[letter] = letter

还有

variables = {'A': 1, 'B': 2, 'C': 3}

for letter in 'ABC': 
    print varaibles[letter]

关于第一个/主要问题,通常情况下,当你调整窗口大小时,网格不会改变单元格的大小。

所以单元格保持原来的大小(它会根据窗口的大小来设置),你只会看到画布的一部分。如果你设置窗口的大小(或者设置画布的大小),你会看到更多的矩形。

但是你可以改变 grid 的行为,让它在你调整窗口大小时调整行或列的大小。

backgroundCanvas.grid(row = 0, column = 0, sticky = N+S+E+W)
root.grid_rowconfigure(0, weight=1) # resize row 0 vertically
root.grid_columnconfigure(0, weight=1) # resize column 0 horizontally

顺便提一下:使用 backgroundCanvas.pack() - 不带参数 - 你也只会看到部分矩形。


Tkinterbook: Tkinter 网格几何管理器, Tkinter 打包几何管理器

撰写回答