我目前正在尝试在画布上显示图像。更具体地说,我想根据窗口的大小调整在画布上绘制的图像的大小(这样,图像就总是适合画布上的大小)。
我从填充整个屏幕的简单画布开始。
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()
您的新代码中存在bug的问题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.
最少的工作代码。
我更改了一些计算以使其更具可读性。
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()
和图像进行测试
维基百科:Lenna
编辑:
我看到其他问题-不太明显。您始终会放上新图像,但不会删除旧图像-因此,最终它可能会占用更多内存。
您可以在开始时将图像放在画布上并获取其ID
image_id = canvas.create_image((0,0), image=testImageTk, anchor="nw")
然后使用ID替换图片
canvas.itemconfig(image_id, image=resizedTestImageTk)
Minimale工作代码:
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.width()
image_height = testImageTk.height()
if window_height < window_width:
proportion = window_height / image_width
else:
proportion = window_width / image_height
image_width = int(image_width * proportion)
image_height = int(image_height * proportion)
resizedTestImage = testImage.resize((image_width, image_height))
resizedTestImageTk = ImageTk.PhotoImage(resizedTestImage)
canvas.itemconfig(image_id, image=resizedTestImageTk)
#canvas.resizedTestImageTk = resizedTestImageTk # <-- assign local `resizedTestImageTk` to global class.
print(f"(image width, image height): ({image_width} {image_height})")
# --- main ---
image_id = None # default value at start
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
image_id = canvas.create_image((0,0), image=testImageTk, anchor="nw")
root.bind("<Configure>", handle_configure)
root.mainloop()
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句