Таким образом, способ, которым я обошел это, заключается в том, чтобы иметь хранилище значений, виджет которого Entry
последний раз обновлялся, и затем иметь функцию «проверки», которая проверяет через крошечные интервалы, чтобы увидеть, был ли обновлен либо Entry
, изатем обновляет другое:
from tkinter import *
class App:
def __init__(self, root):
self.root = root
self.aspect = 2
self.widthvalue = StringVar(name="width")
self.widthvalue.set(1)
self.heightvalue = StringVar(name="height")
self.heightvalue.set(str(int(self.widthvalue.get())*self.aspect))
self.widthvalue.trace("w", lambda name, index, mode, width=self.widthvalue: self.entrychange(width))
self.heightvalue.trace("w", lambda name, index, mode, height=self.heightvalue: self.entrychange(height))
self.width = Entry(self.root, textvariable=self.widthvalue)
self.height = Entry(self.root, textvariable=self.heightvalue)
self.width.pack()
self.height.pack()
self.lastupdated = None
self.root.after(10, self.update)
def entrychange(self, value):
self.lastupdated = str(value)
def update(self):
if self.lastupdated != None:
if self.lastupdated == "width" and self.widthvalue.get() != "" and self.widthvalue.get() != "0":
self.heightvalue.set(str(int(int(self.widthvalue.get())/self.aspect)))
self.height.update()
self.lastupdated = None
elif self.lastupdated == "height" and self.heightvalue.get() != "" and self.heightvalue.get() != "0":
self.widthvalue.set(str(int(self.heightvalue.get())*self.aspect))
self.width.update()
self.lastupdated = None
self.root.after(10, self.update)
root = Tk()
App(root)
root.mainloop()
Давайте разберемся с этим.
Первое, что мы делаем, это устанавливаем соотношение сторон, чтобы придерживаться его. В этом случае мы говорим, что высота всегда будет вдвое больше ширины:
self.aspect = 2
Далее мы создаем StringVar
переменные для хранения значений двух виджетов Entry
и установки их значенийдо абсолютного минимума:
self.widthvalue = StringVar(name="width")
self.widthvalue.set(1)
self.heightvalue = StringVar(name="height")
self.heightvalue.set(str(int(self.widthvalue.get())*self.aspect))
Затем мы устанавливаем трассировки для этих переменных, чтобы при каждом их обновлении мы вызывали функцию entrychange
. Эта функция относительно проста, она просто обновляет другую переменную с именем self.lastupdated
, которая хранит либо width
, либо height
, в зависимости от того, какое Entry
было обновлено в последний раз:
self.widthvalue.trace("w", lambda name, index, mode, width=self.widthvalue: self.entrychange(width))
self.heightvalue.trace("w", lambda name, index, mode, height=self.heightvalue: self.entrychange(height))
Затем мы делаем скучные биты. , нарисуйте виджеты, установите их textvariable
, упакуйте их и установите значение по умолчанию для self.lastupdated
:
self.width = Entry(self.root, textvariable=self.widthvalue)
self.height = Entry(self.root, textvariable=self.heightvalue)
self.width.pack()
self.height.pack()
self.lastupdated = None
После этого мы запускаем вызов .after()
. Что позволяет вам иметь непрерывные циклы в tkinter
:
self.root.after(10, self.update)
Это запускает процесс постоянного запуска нашей функции update
.
Функция обновления начинается с проверки,или нет, либо Entry
было обновлено:
if self.lastupdated != None:
Затем он проверяет, какое из них было обновлено в последний раз, и проверяет, не является ли поле пустым или равно 0. Это потому, что и пустые значения, и 0будет возиться с нашей математикой (а также недопустимыми размерами для изображения):
if self.lastupdated == "width" and self.widthvalue.get() != "" and self.widthvalue.get() != "0":
Затем мы устанавливаем значение противоположного виджета Entry
как двойное или половинное (в зависимости от того, какой Entry
был изменен), обновите виджет в графическом интерфейсе и установите для переменной self.lastupdated
значение по умолчанию:
self.heightvalue.set(str(int(int(self.widthvalue.get())/self.aspect)))
self.height.update()
self.lastupdated = None
Для других Entry
мы делаем более или менее то же самое.