在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, 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_configureresizedTestImageTk即使您已经创建了外部/全局变量,也可以分配给局部变量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] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

pyQt QWidget'闪烁'调整大小并重新绘制

来自分类Dev

如何在画布上重新绘制以调整大小而不会模糊?

来自分类Dev

调整窗口大小时重新绘制/擦除画布

来自分类Dev

在鼠标绘图上重新绘制画布并调整其大小

来自分类Dev

调整窗口大小时重新绘制/擦除画布

来自分类Dev

在画布中绘制时如何调整位图的大小?

来自分类Dev

在画布中调整图像大小

来自分类Dev

在tkinter画布上动态调整矩形大小

来自分类Dev

Tkinter画布无法正确调整大小

来自分类Dev

画布调整图像对象的大小并重复图案

来自分类Dev

从双启动中删除ubuntu 14.04,调整分区大小并重新安装

来自分类Dev

调整大小时重新绘制SVG

来自分类Dev

画布上的Tkinter调整大小滚动条无法调整

来自分类Dev

画布上的Tkinter调整大小滚动条无法调整

来自分类Dev

Tkinter:画布中的可滚动框架:自动调整大小的绑定错误

来自分类Dev

在 HTML 中调整 SVG 大小而不调整画布大小

来自分类Dev

在画布上绘制可调整大小的矩形

来自分类Dev

在tkinter中调整图像大小

来自分类Dev

C#在WPF中重新绘制画布

来自分类Dev

调整画布图像的大小

来自分类Dev

无法调整画布大小

来自分类Dev

如何调整画布大小

来自分类Dev

调整画布图像的大小

来自分类Dev

调整画布元素的大小

来自分类Dev

在画布上更新高度/宽度并重新开始绘制

来自分类Dev

在画布中使用ctx.scale()方法时,重新调整大小和旋转在fabricjs中不起作用吗?

来自分类Dev

在桌面布局和移动布局之间重新调整元素大小并重新排序

来自分类Dev

如何强迫设计师重新绘制调整大小的矩形?

来自分类Dev

强制“ Rallychart”组件在容器调整大小时重新绘制

Related 相关文章

热门标签

归档