tkinter + pillow. Проблема при изменении размеров окна

При изменении размеров окна иногда случается такое, что параметры аргумента event функции on_resize малы, относительно действительного размера окна, поэтому бывает так, что в функции get_gradient_image (которая вызывается из refresh_image) возникает исключение библиотеки PIL ValueError: Width and height must be >= 0 за счет чего программа сильно "пролагивает" в такие моменты.

Пока я использовал pack и place для менеджмента виджетов все было нормально.

Как это можно исправить?

P.S.: Прошу прощения за огромную часть кода, но я учусь программированию совсем недавно.

import os
import tkinter as tk
from PIL import Image, ImageDraw, ImageColor, ImageTk

DLM = ">"
DEFAULT_SETTINGS = {"index": 0, "width": 800, "height": 450}


class Application(tk.Frame):
    def __init__(self, parent):
        tk.Frame.__init__(self, parent)
        self.parent = parent

        top = self.winfo_toplevel()
        top.rowconfigure(0, weight=1)
        top.columnconfigure(0, weight=1)

        self.settings = self.load_settings()
        self.gradients = self.get_gradients("gradients.db", "utf-8")
        
        self.img_gradient = tk.Label(parent, image=None)
        self.img_gradient.grid(row=0, column=0, columnspan=2, sticky="nswe")
        
        self.lbl_score = tk.Label(parent, text="")
        self.lbl_score.grid(row=1, column=1, sticky="e")

        self.lbl_index = tk.Label(parent, text="")
        self.lbl_index.grid(row=1, column=0, sticky="w")

        parent.bind("<Up>", self.inc_score)
        parent.bind("<Down>", self.dec_score)
        parent.bind("<Right>", self.inc_index)
        parent.bind("<Left>", self.dec_index)
        parent.bind("<Configure>", self.on_resize)
        
        parent.protocol("WM_DELETE_WINDOW", self.close_window)
        
        parent.title("Training data generator")
        
        self.refresh_image()
        self.refresh_index()
        self.refresh_score()

        self.lbl_index.update()

    def load_settings(self):
        settings = dict()
        if not os.path.exists("options.cfg"):
            self.save_settings(DEFAULT_SETTINGS)
        with open("options.cfg", "r", encoding="utf-8") as file:
            for line in file:
                param, value = [part.strip() for part in line.split(": ")]
                if param in ("index", "width", "height"):
                    value = int(value)
                settings[param] = value
        return settings

    def save_settings(self, settings=None):
        if settings is None:
            settings = self.settings
        with open("options.cfg", "w", encoding="utf-8") as file:
            for param, value in settings.items():    
                print(f"{param}: {value}", file=file)
    
    def get_gradients(self, filepath, encoding):
        gradients = list()
        
        with open(filepath, "r", encoding=encoding) as file:
             for line in file:
                 gradient = line.strip().split(DLM)
                 gradients.append({"from":  gradient[0],
                                   "to":    gradient[1],
                                   "score": int(gradient[2])})
                 
        return gradients

    def get_gradient_image(self, clr_from, clr_to):
        print(str(self.settings["width"]) + "x" + str(self.settings["height"]))
        im_gradient = Image.new("RGB", (self.settings["width"] -4,
                                        self.settings["height"]-25))
        draw = ImageDraw.Draw(im_gradient)

        clr_from = ImageColor.getrgb(self.gradients[self.settings["index"]]["from"])
        clr_to = ImageColor.getrgb(self.gradients[self.settings["index"]]["to"])
        
        for x in range(self.settings["width"]-4):
            clr_current = list()
            for i in range(3):
                lclr = (1 - x/(self.settings["width"]-1))*clr_from[i]
                rclr = x/(self.settings["width"]-1)*clr_to[i]
                clr_current.append(round(lclr) + round(rclr))
            draw.line([(x, 0), (x, self.settings["height"]-1)], fill=tuple(clr_current))
            
        del draw
        
        return im_gradient

    def save_gradients(self, filepath, encoding):
        with open(filepath, "w", encoding=encoding) as file:
            for gradient in self.gradients:
                print(f"{gradient['from']}{DLM}{gradient['to']}{DLM}{gradient['score']}", file=file)

    def close_window(self):
        self.save_gradients("gradients.db", "utf-8")
        self.save_settings()
        self.parent.destroy()

    def on_resize(self, event):
        self.settings["width"] = event.width
        self.settings["height"] = event.height

        self.refresh_image()

    def refresh_image(self):
        img = ImageTk.PhotoImage(self.get_gradient_image(self.gradients[self.settings["index"]]["from"],
                                                         self.gradients[self.settings["index"]]["to"]))
        self.img_gradient.configure(image=img)
        self.img_gradient.img_ref = img

    def refresh_score(self):
        text = {-2: "CRAPPY",
                -1: "BAD",
                 0: "NEUTRAL",
                 1: "GOOD",
                 2: "BEAUTIFUL"}.get(self.gradients[self.settings["index"]]["score"])
        self.lbl_score.config(text=text)

    def refresh_index(self):
        self.lbl_index.config(text=f"{self.settings['index']+1} / {len(self.gradients)}")

    def inc_score(self, event):
        if self.gradients[self.settings["index"]]["score"] < 2:
            self.gradients[self.settings["index"]]["score"] += 1
        self.refresh_score()

    def dec_score(self, event):
        if self.gradients[self.settings["index"]]["score"] > -2:
            self.gradients[self.settings["index"]]["score"] -= 1
        self.refresh_score()

    def inc_index(self, event):
        if self.settings["index"] < len(self.gradients) - 1:
            self.settings["index"] += 1

        self.refresh_image()
        self.refresh_index()
        self.refresh_score()

    def dec_index(self, event):
        if self.settings["index"] > 0:
            self.settings["index"] -= 1
            
        self.refresh_image()
        self.refresh_index()
        self.refresh_score()


def main():
    root = tk.Tk()
    Application(root)
    root.mainloop()


if __name__ == "__main__":
    main()

Ответы (0 шт):