首页 > 解决方案 > 在 Tkinter 首次运行问题上调整画布大小

问题描述

我想制作一个以小窗口开始的程序,然后当给定图像路径时,它会最大化屏幕并将图像放在中心。

如果你运行下面的代码,你会看到窗口最大化,图像被加载到内存中,代码运行没有错误,self.open_image调用self.draw_image(self.pimg)也没有错误,但是图像不在画布上。

如果我单击“修复”按钮并调用self.fix它,它将self.draw_image(self.pimg)正常运行并正确绘制图像。

如何使用相同的参数两次调用相同的函数并获得不同的结果。有什么不同吗。

我感觉这是正在发生的事情,因为在主循环中发生了一些在结尾没有发生的事情self.__init__,所以当我self.draw_image第二次调用时self.cv.create_image,能够与可调整大小的画布中的某些内容进行交互。

在这个例子中,我很高兴假设程序将始终作为一个小窗口开始并成为一个最大化的窗口,直到它被关闭,永远不会再次调整大小,但是在我的实际程序中,我想让它在窗口处理调整大小时更加动态明智地,这只是一个最小的可重现示例。正是出于这个原因,我想使用 ResizingCanvas 类(或类似的类),即使我觉得这很可能是我遇到的问题的原因。

self.cv我尝试过使用断点并单步执行代码来观察变量的创建,但我看不到第一次和self.cv单击按钮后的区别。

我在这个问题上读到了一个类似的问题,他建议绑定"<Configure>"到画布并将坐标从事件传递到画布。然而,这已经在ResizingCanvas

from tkinter import *
from PIL import Image, ImageTk

class ResizingCanvas(Canvas):
    # https://stackoverflow.com/a/22837522/992644
    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)

class main():
    def __init__(self, name = None):
        self.root = Tk()
        self.name = name # Filename
        myframe = Frame(self.root)
        myframe.pack(fill=BOTH, expand=YES)
        self.cv = ResizingCanvas(myframe, width=850, height=400, bg="dark grey", highlightthickness=0)
        self.cv.pack(fill=BOTH, expand=YES)
        self.b = Button(self.cv, text = 'Fix', command = self.fix).grid(row=1,column=1)
        self.open_img()

    def draw_image(self, img, x = None, y = None):
        """ Handles the drawing of the main image"""
        self.img = ImageTk.PhotoImage(img)
        self.cv.create_image(self.root.winfo_screenwidth()/2, 
                             self.root.winfo_screenheight()/2, image=self.img, tags=('all'))

    def open_img(self, event=''):
        self.pimg = Image.open(self.name)
        self.root.state("zoomed")
        self.draw_image(self.pimg)

    def fix(self, event=''):
        self.draw_image(self.pimg)

    def run(self):
        self.root.mainloop()

if __name__ == "__main__":
    path = 'example.png'
    app = main(path)
    app.run()

视频中应该发生的事情:我点击运行,图像立即显示,无需点击修复按钮。

视频中发生了什么:我点击运行,直到我点击修复按钮,图像才会显示,之后它就可以工作了。 错误的屏幕截图

标签: pythonpython-3.xtkinterpython-imaging-librarytkinter-canvas

解决方案


改变

self.root.state("zoomed")self.root.state("normal")

在您的代码中(我正在使用 Python3)我只能得到:

[https://stackoverflow.com/questions/22835289/how-to-get-tkinter-canvas-to-dynamically-resize-to-window-width1

上图,从How to get tkinter canvas to dynamic resize to window width?开始播放了一点点?

现在代码似乎对我有用:

from time import sleep

from tkinter import *
from PIL import Image, ImageTk

class ResizingCanvas(Canvas):
    # https://stackoverflow.com/a/22837522/992644
    def __init__(self,parent, **kwargs):
        # Canvas.__init__(self,parent,**kwargs)
        print(kwargs)
        Canvas.__init__(self,parent,**kwargs)
        self.bind("<Configure>", self.on_resize)
        # self.height = self.winfo_reqheight()
        # self.width = self.winfo_reqwidth()
        self.height = self.winfo_height()
        self.width = self.winfo_width()
        # self.height = height
        # self.width = width
        # self.__dict__.update(kwargs)

    def on_resize(self,event):
        """ determine the ratio of old width/height to new width/height"""
        wscale = (event.width)//self.width
        hscale = (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)

class main():
    def __init__(self, name = None):
        self.pippo = Tk()
        self.name = name # Filename
        self.myframe = Frame(self.pippo)
        self.myframe.pack(side = BOTTOM, expand=YES)
        # myframe.pack(fill=BOTH, expand='TRUE')
        self.cv = ResizingCanvas(self.myframe, width=850, height=400, bg="dark grey", highlightthickness=0)
        self.cv.pack(fill=BOTH, expand=YES)
        # sleep(2)
        self.b = Button(self.myframe, text = 'Fix', command = self.fix)#.grid(row=1,column=1)
        self.b.pack(side=TOP)
        self.open_img()
        # self.pippo.mainloop()  ## use it if you eliminate def run

    def draw_image(self, img, x = None, y = None):
        """ Handles the drawing of the main image"""
        self.img = ImageTk.PhotoImage(img)
        # self.cv.create_image(self.pippo.winfo_screenwidth()/2, 
        #                      self.pippo.winfo_screenheight()/2, image=self.img, tags=('all'))
        self.cv.create_image(self.pippo.winfo_width()/2, 
                             self.pippo.winfo_reqheight()/2, image=self.img, tags=('all'))

    def open_img(self, event=''):
        self.pimg = Image.open(self.name)
        self.pippo.state("normal")
        self.draw_image(self.pimg)

    def fix(self, event=''):
        self.draw_image(self.pimg)

    def run(self):
        self.pippo.mainloop()

if __name__ == "__main__":
    path = 'example.png'
    app = main(path)
    app.run()

虽然不知道您的问题,但想确保您的起始示例正常工作。让我知道它是否与 python/pillow/tkinter 版本或其他有关

这是我按下修复按钮后在广告之前的窗口图像结果:

在此处输入图像描述

在此处输入图像描述

最后发现只要你使用你的代码就可以工作

self.root.attributes('-zoomed', True) instead of `self.root.state("zoomed")`

推荐阅读