微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

在 tkinter 中调整大小和重绘画布

如何解决在 tkinter 中调整大小和重绘画布

我目前正在尝试在画布上显示图像。更具体地说,我想让画布上绘制的图像根据窗口的大小调整大小(这样图像总是适合画布)。

我从一个填满整个屏幕的简单画布开始。

import tkinter as tk
from PIL import Image,ImageTk

root = tk.Tk()
WIDTH,HEIGHT = root.winfo_screenwidth(),root.winfo_screenheight()
root.geometry('%dx%d+0+0' % (WIDTH,HEIGHT))

canvas = tk.Canvas(root)
canvas.pack(fill="both",expand=True)

然后我会设置我的背景图像和能够在背景上调整大小的图像。

backgroundImage = ImageTk.PhotoImage(Image.open("filepath"))
image1 = Image.open("filepath")
image2 = ...
....
....

然后我创建了一种调整图像大小的方法

"""
This method resizes a image so that all the images fits on the GUI. This first creates an Image object,but since the Image object does not allow access to the width and height of the Image object,a ImageTk
object needs to be created from the Image object. The ImageTk object cannot resize,but the Image object
can. So using ImageTk object to get the height and width and the Image object to resize,a new Image object
that is resized to fit the GUI is created.
@imageFile- the image file that is being resized
@windowMeasure- the measurement of the window to proportionally resize the image
@useHeight- determine the measurement being proportioned
"""
def resizedImageTk(image,windowMeasure,useHeight):
    imageTk = ImageTk.PhotoImage(image)
    area = windowMeasure * 4/5
    tileSize = area / 4
    if useHeight:
        proportion = tileSize / imageTk.height()
    else:
        proportion = tileSize / imageTk.width()
    resizedImage = image.resize((int(imageTk.width()*proportion),int(imageTk.height()*proportion)))
    resizedImageTk = ImageTk.PhotoImage(resizedImage)
    return resizedImageTk

然后我使用一种方法在窗口大小发生变化时重新绘制调整大小的图像并将其绑定到根。注意:我知道这可能需要大量计算,因此我减少了这种情况发生的次数

numResizes = 0
def handle_configure(event):
    if numResizes % 5 == 0:
        geometry = root.geometry()
        width = int(geometry[0:geometry.index("x")])
        height = int(geometry[geometry.index("x")+1:geometry.index("+")])
        canvas.create_image((0,0),image=backgroundImageTk,anchor="nw")

        if height < width:
            measurement = height
        else:
            measurement = width

        resizedImage1 = resizedImageTk(image1,measurement,height < width)
        resizedImage2 = ....
        ....
        ....

   
        images = [resizedImage1,resizedImage2,...]
    
        imageWidth = resizedImage1.width()
        imageHeight = resizedImage1.height()
    
        i = 0
        for row in range(0,int(len(images) / 4)):
            for column in range(0,int(len(images) / 5):
                x = imageWidth*column + int(width/2) - imageWidth * 2
                y = imageHeight*row + int(height/2) - int(imageHeight*2.5)
                canvas.create_image((x,y),image=images[i])
                i=i+1
    numResizes = numResizes + 1  
root.bind("<Configure>",handle_configure)
root.mainloop()

我已经用我的图像运行了这个并取得了一些成功,但是,它不能完全工作。我有我的背景图片显示,但我的其他图片没有。我不知道为什么,因为当我在嵌套 for 循环(未显示图像的位置)中对画布使用 create_line 函数时,我确实显示了线条。

如果有人能就此提供一些建议,我将不胜感激!

谢谢

更新:

这是我正在尝试做的一个简单示例。您可以使用任何示例图片来对此进行测试。

import tkinter as tk
from PIL import Image,HEIGHT = int(root.winfo_screenwidth() * 103/104),int(root.winfo_screenheight() * 11/12)
root.geometry('%dx%d+0+0' % (WIDTH,expand=True)

testimage = Image.open("enter file path here!")
testimageTk = ImageTk.PhotoImage(testimage)

resizedTestimage = None
resizedTestimageTk = None

def handle_configure(event):
    geometry = root.geometry()
    width = int(geometry[0:geometry.index("x")])
    height = int(geometry[geometry.index("x")+1:geometry.index("+")])
    
    useHeight = height < width
    if useHeight:
        measurement = height
    else:
        measurement = width

    if useHeight:
        proportion = measurement / testimageTk.height()
    else:
        proportion = measurement / testimageTk.width()
    
    resizedTestimage = testimage.resize((int(testimageTk.width()*proportion),int(testimageTk.height()*proportion)))
    resizedTestimageTk = ImageTk.PhotoImage(resizedTestimage)
    canvas.create_image((0,image=resizedTestimageTk,anchor="nw")
    print("(image width,image height): (" + str(resizedTestimageTk.width()) + " " + str(resizedTestimageTk.height()) + ")")

root.bind("<Configure>",handle_configure)

root.mainloop()

解决方法

您的新代码在 PhotoImage 中存在错误。

handle_configure 中,即使您已经创建了外部/全局变量 resizedTestImageTk

如果我通知函数它必须使用 resizedTestImageTk 来通知函数它必须将它分配给外部变量而不是本地变量,这对我有用

global

或者我将本地 def handle_configure(event): global resizedTestImageTk # <-- inform function to assign image to global variable instead of using local one 分配给全局类。

resizedTestImageTk

最少的工作代码。

我更改了一些计算以使其更具可读性。

canvas.resizedTestImageTk = resizedTestImageTk   # <-- assign local `resizedTestImageTk` to global class.

和测试图像

enter image description here

维基百科:Lenna


编辑:

我看到了其他问题 - 不太明显。您总是放置新图像但不会删除旧图像 - 所以最终它可能会使用更多内存。

您可以在开始时将图像放在画布上 - 并获取其 ID

import tkinter as tk
from PIL import Image,ImageTk

# --- functions ---

def handle_configure(event):
    global resizedTestImageTk   # <-- inform function to assign image to global variable instead of using local one
    
    geometry = root.geometry()    
    window_width  = int(geometry[0:geometry.index("x")])
    window_height = int(geometry[geometry.index("x")+1:geometry.index("+")])
    
    image_width  = testImageTk.height()
    image_height = testImageTk.width()
    
    if window_height < window_width:
        proportion = window_height / image_height
    else:
        proportion = window_width / image_width
     
    image_width  = int(image_width  * proportion)
    image_height = int(image_height * proportion)
    
    resizedTestImage   = testImage.resize((image_width,image_height))
    resizedTestImageTk = ImageTk.PhotoImage(resizedTestImage)
    canvas.create_image((0,0),image=resizedTestImageTk,anchor="nw")
    #canvas.resizedTestImageTk = resizedTestImageTk   # <-- assign local `resizedTestImageTk` to global class.

    print(f"(image width,image height): ({image_width} {image_height})")

# --- main ---

root = tk.Tk()
WIDTH =  int(root.winfo_screenwidth() * 103/104)
HEIGHT = int(root.winfo_screenheight() * 11/12)

root.geometry('%dx%d+0+0' % (WIDTH,HEIGHT))

canvas = tk.Canvas(root)
canvas.pack(fill="both",expand=True)

testImage = Image.open("lenna.png")
testImageTk = ImageTk.PhotoImage(testImage)

resizedTestImage = None
resizedTestImageTk = None

root.bind("<Configure>",handle_configure)

root.mainloop()

然后使用 ID 替换图像

image_id = canvas.create_image((0,image=testImageTk,anchor="nw")

最小工作代码:

canvas.itemconfig(image_id,image=resizedTestImageTk)

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。