Python / tkinter: дважды изменить метку за одно выполнение команды - PullRequest
0 голосов
/ 09 января 2019

Допустим, у нас есть три виджета tkinter: метка, древовидная структура и Optionmenu (для краткости ниже будем называть «меню»). Я успешно заставляю меню выполнять функцию после выбора опции. Краткая функция выглядит так:

def data_process():
    # do something takes time
def print_data()
    data_process() # do something takes time too
    # print stuff to treeview
def refresh_table(self, args):
    label['text'] = 'Executing' # change label text to Executing
    print_data()                # a func. which takes time to run
    label['text'] = 'Done'      # change text to Done
label = tk.Label(parent, text = 'ready')
label.pack()
menu = tk.OptionMenu(parent, var, *list, command = lambda _:refresh_table(self, args))
menu.pack()
table = tk.Treeview(parent)
table.pack()

Функция print_data собирается что-то напечатать в виджет дерева (таблица). Виджет метки похож на строку состояния, сообщая пользователям, что происходит сейчас. Итак, рабочий процесс, который я пытаюсь сделать:

  1. Выберите опцию в меню и позвоните refresh_table.

  2. Изменить текст метки на «Выполнение».

  3. Выполнить print_data и распечатать материал в виде дерева.

  4. Когда print_data сделано, измените метку на «Готово».

Вот эта вещь. Когда я выбираю опцию, программа запасается (как и ожидалось), чтобы делать вещи. Тем не менее, ярлык не меняется на «Выполнение» в начале. Вместо этого оно изменяется на «Готово», когда print_data завершается (почти одновременно). Я подозреваю, что команда refresh_table воздействует на целевые виджеты после выполнения всех требований. Потому что я вижу, что ярлык мигает «Выполнено», но сразу показывает «Готово». Есть какие-нибудь мысли об этой ситуации? Любое предложение приветствуется. Спасибо!

1 Ответ

0 голосов
/ 09 января 2019

Я подозреваю, что команда refresh_table воздействует на целевые виджеты после выполнения всех требований.

Это правда. Ваш графический интерфейс будет обновляться каждый раз, когда вводится mainloop. Пока ваша функция refresh_table запущена, никакие события (например, обновление вашей метки) не будут обрабатываться, поскольку они происходят только во время простоя (отсюда и другое название - «пустые задачи»). Но поскольку пользовательский интерфейс не простаивает во время выполнения refresh_table, цикл обработки событий недоступен до тех пор, пока весь код функции не будет выполнен (поскольку вся ваша программа выполняется в одном потоке) и событие перерисовки не будет выполнено. Вы можете исправить это, вызвав update_idletasks, который немедленно обработает все ожидающие события. Это будет сделано так (при условии, что ваше главное окно называется parent и вы находитесь внутри определения класса, важно, чтобы вы вызывали update_idletasks в главном окне сразу после изменения текста метки):

def refresh_table(self, args):
    label['text'] = 'Executing'
    self.parent.update_idletasks()
    print_data()
    label['text'] = 'Done'

Существует также update, который будет не только вызывать незавершенные незанятые задачи, но и обрабатывать в основном все, что есть, для обработки, что в вашем случае не нужно. Очень хорошее объяснение, почему update_idletasks в основном предпочтительнее update, можно найти в ответе на этот вопрос .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...