简体   繁体   English

Tkinter画布自动调整大小

[英]Tkinter canvas resizing automatically

So in the process of answering this question , I came across some odd behaviour from Tkinter. 所以在回答这个问题的过程中,我遇到了Tkinter的一些奇怪的行为。 I have a class that resizes a Canvas instance and any widgets drawn on it. 我有一个类来调整Canvas实例的大小以及在其上绘制的任何小部件。 However when I run the code, regardless of the initial window dimensions, the window expands continuously until it fills the entire screen. 但是,当我运行代码时,无论初始窗口尺寸如何,窗口都会不断扩展,直到它填满整个屏幕。 After this happens, the window behaves exactly as expected, resizing the objects properly. 发生这种情况后,窗口的行为与预期完全一致,正确调整对象的大小。 The window only expands to fill the screen on launch. 该窗口仅在启动时展开以填充屏幕。

From reading the Tkinter docs I could believe that this may be platform specific (I don't have any proof though). 通过阅读Tkinter文档,我可以相信这可能是特定于平台的(尽管我没有任何证据)。

My question is: Why does this happen? 我的问题是:为什么会这样? How can I stop it? 我怎么能阻止它?

The code is below: 代码如下:

from Tkinter import *

# a subclass of Canvas for dealing with resizing of windows
class ResizingCanvas(Canvas):
    def __init__(self,parent,**kwargs):
        Canvas.__init__(self,parent,**kwargs)
        self.bind("<Configure>", self.on_resize)
        self.height = self.winfo_reqheight()
        self.width = self.winfo_reqwidth()

    def on_resize(self,event):
        # determine the ratio of old width/height to new width/height
        wscale = float(event.width)/self.width
        hscale = float(event.height)/self.height
        self.width = event.width
        self.height = event.height
        # resize the canvas 
        self.config(width=self.width, height=self.height)
        # rescale all the objects tagged with the "all" tag
        self.scale("all",0,0,wscale,hscale)

def main():
    root = Tk()
    myframe = Frame(root)
    myframe.pack(fill=BOTH, expand=YES)
    mycanvas = ResizingCanvas(myframe,width=850, height=400, bg="red")
    mycanvas.pack(fill=BOTH, expand=YES)

    # add some widgets to the canvas
    mycanvas.create_line(0, 0, 200, 100)
    mycanvas.create_line(0, 100, 200, 0, fill="red", dash=(4, 4))
    mycanvas.create_rectangle(50, 25, 150, 75, fill="blue")

    # tag all of the drawn widgets
    mycanvas.addtag_all("all")
    root.mainloop()

if __name__ == "__main__":
    main()

We've established that highlightthickness , an option of Canvas , is the culprit for this behavior, and setting it to 0 fixes the issue. 我们已经建立了highlightthickness的一种选择Canvas ,是针对此行为的罪魁祸首,并将其设置为0修复该问题。

Here's why (I think) it happens: 这就是为什么(我认为)它会发生的原因:

From http://effbot.org/tkinterbook/tkinter-events-and-bindings.htm 来自http://effbot.org/tkinterbook/tkinter-events-and-bindings.htm

Configure The widget changed size (or location, on some platforms). 配置 窗口小部件更改大小(或在某些平台上的位置)。 The new size is provided in the width and height attributes of the event object passed to the callback. 新大小在传递给回调的事件对象的width和height属性中提供。

This is the stripped down version of the Canvas subclass: 这是Canvas子类的精简版:

class ResizingCanvas(Canvas):
    def __init__(self,parent,**kwargs):
        Canvas.__init__(self,parent,**kwargs)
        print self.winfo_reqwidth(),self.winfo_reqheight() #>>>854, 404
        self.bind("<Configure>", self.on_resize)

    def on_resize(self,event):
        self.width = event.width   #>>>854
        self.height = event.height #>>>404
        self.config(width=self.width, height=self.height)

So, <Configure> should operate like this: 所以, <Configure>应该像这样运行:

  1. Detect resize 检测调整大小
  2. Call function 通话功能
  3. Set Canvas to new size 将画布设置为新大小

But it's doing this: 但它正在这样做:

  1. Detect resize 检测调整大小
  2. Call function 通话功能
  3. Set Canvas to new size 将画布设置为新大小
  4. Detect resize, repeat 检测调整大小,重复

What's happening between 3 & 4? 3到4之间发生了什么? Well, the Canvas is being set to a new size (its previous size + 4), but after that, the highlightthickness changes the actual size to +4 of that, which triggers <Configure> in an endless loop until the screen width is hit and it breaks. 好吧,Canvas被设置为一个新的大小(之前的大小+4),但之后,highlightthickness将实际大小更改为+4,这将在无限循环中触发<Configure>直到屏幕宽度被击中它打破了。

At that point, normal resizing can occur, because it's got just one size to work off of (the combined highlight and canvas size), and it functions normally. 此时,可以进行正常的调整大小,因为它只有一个尺寸可以处理(组合的高光和画布大小),并且它正常运行。 If you added a button that resized the canvas and pressed it after the canvas stopped expanding, it would resize, then get weird again and start expanding. 如果你添加了一个按钮来调整画布大小并在画布停止展开后按下它,它会调整大小,然后再次变得怪异并开始扩展。

I hope that kind of explained it. 我希望能解释一下。 I'm not 100% sure that this is 100% correct, so if anyone has corrections, feel free. 我不是100%确定这是100%正确,所以如果有人有更正,请随意。

I think the original problem is the recursive behaviour of on_resize() which is binding to Configure event, and resize() also calls "self.config(width=self.width, height=self.height)" - which will trigger the Configure event again. 我认为最初的问题是on_resize()的递归行为,它绑定到Configure事件,resize()也调用“self.config(width = self.width,height = self.height)” - 这将触发配置事件再次。 Remove "self.config(width=self.width, height=self.height)" will fix the problem. 删除“self.config(width = self.width,height = self.height)”将解决问题。

Apparently setting "highlightthickness=0" also fix the problem - I am guess the window layout manager has some magic detecting there is no change in the window size hence stop calling on_resize() recursively 显然设置“highlightthickness = 0”也解决了问题 - 我猜测窗口布局管理器有一些魔法检测窗口大小没有变化因此停止以递归方式调用on_resize()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM