在 tkinter 中调整画布图像大小的问题 [英] Issues resizing a canvas image in tkinter

查看:147
本文介绍了在 tkinter 中调整画布图像大小的问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在创建一个自定义 tkinter Frame 类以用于更大的项目.我现在已经可以使用它了,但是它有问题.调用时,该类应创建一个小部件,该小部件在画布对象的上方和左侧创建复选按钮,上面有一个图像项.我遇到的两个问题:

I'm creating a custom tkinter Frame class for use in a larger project. I've got it in a usable state now, but it's buggy. When called, the class should create a widget that creates checkbuttons above and to the left of a canvas object with an image item on it. 2 issues I'm having with this:

1) 当第一次执行时,代码几乎按照需要创建了整个小部件,除了画布上的图像直到发生调整大小事件才会出现,比如我抓住窗口的一侧并调整它的大小.

1) When first executed, the code creates the entire widget almost as wanted, except the image on the canvas doesn't appear until a resize event occurs, say I grab a side of the window and resize it.

画布上没有图像

2) 然后,当发生调整大小事件时,图像并不总是完全正确调整大小.很多时候,特别是如果通过快速移动光标来调整大小,画布最终可能会比图像大,或者图像可能会被窗口边缘切掉一点.在我在下面链接的错误调整大小图像中,画布是图像下方的黑色尖峰.为什么图片每次都与画布大小不匹配?

2) Then ,when a resize event occurs, the image doesn't always resize exactly right. Very often, especially if the resize is done with a quick jerk of the cursor, the canvas can end up larger than the image, or the image can be cut off a bit by the edge of the window. In the bad resize image I linked below, the canvas is the black peaking from beneath the image. Why is the image not matching the canvas in size every time?

调整大小

调整大小错误

请注意,当我使用全屏按钮时,图像根本不会调整大小.然后当我使用窗口按钮时,图像会调整为全屏大小,从而在小窗口内产生一个巨大的图像.调整大小事件似乎执行了一个步骤,导致我认为我以某种方式滥用了事件队列,尽管我不确定这是否是我的两个问题的根源...

Of note, when I use the fullscreen button, the image doesn't resize at all. When I then use the windowed button, the image resizes to the fullscreen size, resulting in a huge image inside the small window. The resize event seems to be executing a step behind, leading me to think I'm misusing the event queue somehow, though I'm not sure that's the source of both my issues...

有什么想法吗?

import tkinter as tk
from PIL import Image, ImageTk

KATA_CHART = "../assets/kata_chart.png"
HIRA_CHART = "../assets/hira_chart.png"

class KanaChart(tk.Frame):

    def __init__(self, master, kana_type, **kwargs):

        super().__init__(master, **kwargs)
        self.build_chart(kana_type)

    def _resize_callback(self, *args):        

        width = self.canvas.winfo_width()
        height = self.canvas.winfo_height()

        self.img = self.original.resize((width, height))
        self.img = ImageTk.PhotoImage(image=self.img)        
        self.canvas.itemconfig(self.canvas_img, image=self.img)

    def build_chart(self, kana_type):

        vowels = "AIUEO"
        consonants = " KSTNHMYRWNGZDBP"
        let_var_dict = {}
        for letter in vowels + consonants:
            var = tk.BooleanVar()
            let_var_dict[letter] = var

        for i in range(6):
            self.grid_rowconfigure(i, weight=1)
        for i in range(17):
            self.grid_columnconfigure(i, weight=1)

        # build the checkbuttons
        for i in range(5):
            letter = vowels[i]
            row = i + 1
            var = let_var_dict[letter]
            b = tk.Checkbutton(self, text=letter, relief=tk.GROOVE, var=var,
                command=self._checkb_wrapper("r", row, var))
            b.grid(row=row, column=0, sticky="nsew")
        for i in range(16):
            letter = consonants[i]
            column = i + 1
            var = let_var_dict[letter]
            b = tk.Checkbutton(self, text=letter, relief=tk.GROOVE, var=var,
                command=self._checkb_wrapper("r", column, var))
            b.grid(row=0, column=column, sticky="nsew")

        # build the canvas with the chart on it
        if kana_type == "hira":
            self.original = Image.open(HIRA_CHART)
        elif kana_type == "kata":
            self.original = Image.open(KATA_CHART)
        self.canvas = tk.Canvas(self, bg="black")
        self.canvas.grid(row=1, column=1, rowspan=5, columnspan=16,
            sticky="nsew")
        self.img = ImageTk.PhotoImage(image=self.original)        
        self.canvas_img = self.canvas.create_image(0, 0, image=self.img,
            anchor=tk.NW)
        self._resize_callback(None)
        self.bind("<Configure>", self._resize_callback)

root = tk.Tk()
chart = KanaChart(root, "kata")
chart.pack(fill=tk.BOTH, expand=1)
root.mainloop()

我曾考虑将我正在使用的图像切成较小的方块,因此我最终会得到 80 张小图像,我可以将它们与小部件网格中的每个单元格匹配,但我假设了一张大图像比 80 个小图像更有效地调整大小.无论如何,不​​要认为这会绕过我现在遇到的问题.

I've considered chopping up the image I'm using into smaller squares, so I'd end up with 80 small images that I could just match to each cell in my widget's grid, but I've assumed one large image is more efficient to resize than 80 small images. Don't think that would circumnavigate the issue I'm having now, anyway.

推荐答案

由于 事件绑定在 self(框架)上,画布不是执行回调时调整大小.在 _resize_callback() 开头添加 self.canvas.update() 可以解决问题.

Since <Configure> event is bound on self (the Frame), the canvas is not yet resized when the callback is executed. Adding self.canvas.update() at the beginning of _resize_callback() may solve the issue.

最好在画布上绑定 事件.然后使用事件对象的宽度和高度属性:

It is better to bind <Configure> event on the canvas instead. Then using width and height attributes of the event object:

def _resize_callback(self, event):
    width, height = event.width, event.height

    self.img = self.original.resize((width, height))
    self.img = ImageTk.PhotoImage(image=self.img)
    self.canvas.itemconfig(self.canvas_img, image=self.img)

同时更新绑定:

def build_chart(self, kana_type):
    ...
    #self._resize_callback(None)  # no need to call here
    self.canvas.bind("<Configure>", self._resize_callback)

顺便说一句,build_chart() 中的两个 for 循环中的以下代码行存在问题:

BTW, there is issue in the following line of your code in the two for loops inside build_chart():

b = tk.Checkbutton(self, text=letter, relief=tk.GROOVE, var=var,
                   command=self._checkb_wrapper("r", row, var))
...
b = tk.Checkbutton(self, text=letter, relief=tk.GROOVE, var=var,
                   command=self._checkb_wrapper("r", column, var))

应该是:

b = tk.Checkbutton(self, text=letter, relief=tk.GROOVE, var=var,
                   command=lambda row=row, var=var: self._checkb_wrapper("r", row, var))
...
b = tk.Checkbutton(self, text=letter, relief=tk.GROOVE, var=var,
                   command=lambda column=column, var=var: self._checkb_wrapper("r", column, var))

这篇关于在 tkinter 中调整画布图像大小的问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆