【发布时间】:2021-04-28 03:45:23
【问题描述】:
我目前正在尝试在画布上显示图像。更具体地说,我想让画布上绘制的图像根据窗口的大小调整大小(这样图像总是适合画布)。
我从一个填满整个屏幕的简单画布开始。
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, ImageTk
root = tk.Tk()
WIDTH, HEIGHT = int(root.winfo_screenwidth() * 103/104), 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("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,0), image=resizedTestImageTk, anchor="nw")
print("(image width, image height): (" + str(resizedTestImageTk.width()) + " " + str(resizedTestImageTk.height()) + ")")
root.bind("<Configure>", handle_configure)
root.mainloop()
【问题讨论】:
-
<Configure>即使您只移动窗口也可以执行 - 您可以使用event.width, event.height并与之前的值event.width, event.height进行比较来识别窗口是否已调整大小。 -
也许您在 PhotoImage 中遇到错误,当图像被分配给局部变量时,它会从内存中删除图像 - 您可能必须将图像分配给全局变量或某个类中的变量。请参阅页面末尾的注意PhotoImage
-
问题是图像的信息(宽度和高度)仍然存在(我已经测试了打印使用图像宽度和高度的坐标)。可能是图像中像素(颜色)的信息被清除了。我想如果那是问题,我可以取消我的代码。我会试试这个。谢谢!
-
正如我所说的
PhotoImage有bug,它会从内存中删除图像,你可能会得到空图像。 -
好吧,我几乎尝试了所有方法,但仍然没有运气。我首先在 handle_configure 方法中做了所有事情,但没有奏效。然后,我将所有信息(ImageTk 对象、调整大小的 Image 对象和调整大小的 ImageTk 对象)存储为全局变量,但仍然无法正常工作。
标签: python user-interface tkinter python-imaging-library tkinter-canvas