Цикл while
работает точно так, как задумано. Фактически вы попросили его заснуть на 15 000 секунд, вот что он делает. Пока он находится в спящем режиме, tkinter не может обновить отображение или обработать события любого типа.
При создании графических интерфейсов эмпирическое правило заключается в том, что вы никогда не должны иметь большой цикл while
в том же потоке, что и графический интерфейс. Графический интерфейс уже имеет бесконечный цикл, работающий все время.
Итак, первый шаг — переместить код, который находится внутри вашего цикла, в функцию. В пользовательском интерфейсе часто полезно отделить код пользовательского интерфейса от кода, не связанного с пользовательским интерфейсом, поэтому в этом случае я рекомендую две функции: одну для выполнения вычислений и одну для обновления отображения. Это упростит замену пользовательского интерфейса или метода расчета без необходимости переписывать всю программу. Это также упростит тестирование функции расчета с помощью модульного теста.
Итак, давайте начнем с функции, которая вычисляет количество смертей. Основываясь на комментариях к другим ответам, кажется, что у вас есть сложная формула для этого, но простое увеличение суммы достаточно для моделирования.
def update_deaths():
global totalDeaths
totalDeaths += 1
Далее вам нужен способ отображения этих смертей. В опубликованном вами коде нет способа сделать это, поэтому это решение требует добавления Label
для отображения текущих смертей. Как вы это сделаете на самом деле, зависит от вас, но следующий код иллюстрирует общий принцип:
death_label = Label(...)
...
def update_display():
global totalDeaths
death_label.configure(text=f"Total Deaths: {totalDeaths}")
Третья часть головоломки — это код для имитации цикла while
. Его задача — обновлять информацию о смертях, а затем обновлять отображение каждую секунду, пока не погибнет все население.
Мы делаем это с помощью метода after
, который может запланировать запуск функции в будущем. Используя after
вместо сна, он позволяет mainloop
продолжать обрабатывать такие события, как нажатия кнопок, нажатия клавиш, запросы на обновление дисплея и т. д.
def simulate_deaths():
global totalDeaths
global totalPopulation
update_deaths()
update_display()
if totalDeaths < totalPopulation:
root.after(1000, simulate_deaths)
Если вы вызываете эту функцию один раз в начале вашей программы, она будет вызываться раз в секунду, пока условие не будет выполнено.
Метод after
возвращает идентификатор, который можно использовать для отмены функции перед ее следующей итерацией. Если вы сохраните это в глобальной переменной (или переменной экземпляра, если вы используете классы), вы можете остановить симуляцию, вызвав after_cancel
с этим идентификатором.
Например:
def simulate_deaths():
global after_id
...
after_id = root.after(1000, simulate_deahts)
def stop_simulation():
root.after_cancel(after_id)
08.02.2021