簡體   English   中英

在 tkinter 中調整 canvas 圖像大小的問題

[英]Issues resizing a canvas image in tkinter

我正在創建一個自定義 tkinter 框架 class 用於更大的項目。 我現在把它裝在一個可用的 state 中,但它有問題。 調用時,class 應該創建一個小部件,該小部件在 canvas object 的上方和左側創建帶有圖像項的復選按鈕。 我遇到的2個問題:

1) 首次執行時,代碼幾乎按照需要創建整個小部件,除了 canvas 上的圖像直到發生調整大小事件才會出現,比如我抓住 window 的一側並調整它的大小。

canvas 上沒有圖像

2)然后,當發生調整大小事件時,圖像並不總是完全正確地調整大小。 很多時候,特別是如果使用 cursor 快速調整大小,canvas 最終會比圖像大,或者圖像可能會被 Z05B8C74CBD96FBF2DE4C1A3527 的邊緣切掉一點。 在我下面鏈接的錯誤調整大小圖像中,canvas 是圖像下方的黑色峰值。 為什么每次圖像大小都與 canvas 不匹配?

很好的調整大小

錯誤調整大小

值得注意的是,當我使用全屏按鈕時,圖像根本不會調整大小。 然后當我使用窗口按鈕時,圖像會調整為全屏大小,從而在小 window 內產生一個巨大的圖像。 調整大小事件似乎落后了一步,導致我認為我以某種方式濫用了事件隊列,盡管我不確定這是我的兩個問題的根源......

有任何想法嗎?

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 個小圖像的大小。 無論如何,不要認為這會繞過我現在遇到的問題。

由於<Configure>事件綁定在self (幀)上,因此執行回調時 canvas 尚未調整大小。 self.canvas.update()開頭添加 self.canvas.update _resize_callback()可能會解決問題。

最好在 canvas 上綁定<Configure>事件。 然后使用事件 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 循環中,以下代碼行存在問題:

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))

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM