Python Tkinter sleep / после не работает как положено - PullRequest
0 голосов
/ 14 октября 2019

Итак, я хочу сделать так, чтобы в скрипте B была функция, которая будет вызываться внутри скрипта A. Так что эта функция будет выводить некоторые данные на консоль через print, но я хочу, чтобы выводтакже должен отображаться на виджете, а сценарий A - это тот, где происходят все мои операции с графическим интерфейсом.

Поэтому я передал функцию X в качестве аргумента функции Y в сценарии B, поэтому, когда этот вывод был напечатан в функции Y, я просто сослался на это в переменную и передалпеременная в функцию X сценария A ... которую я передал в качестве аргумента. Таким образом, эта функция просто вставила вывод в текстовый виджет.

Но проблема в том, что функция Y была вызвана после нажатия кнопки, и по какой-то причине кнопка зависает на некоторое время, а затем отображает окончательный вариантвыводить все сразу. Но это не то, что я хочу. Я хочу, чтобы вывод отображался одновременно с отображением в консоли, один за другим, таким образом. Но похоже, что виджет кнопки возобновляется, когда вся функция, переданная в аргументе команды, завершилась.

Чтобы решить эту проблему, я попытался использовать функции sleep и after, но, похоже, они мне не очень помогают. ,Таким образом, я попытался воссоздать свою проблему более простым способом, и я попытался сделать это, используя сон и после, но ни один из них, кажется, не работает для меня.

Итак, коды приведены ниже, хотя они не совсем соответствуют моей проблеме, но я надеюсь, что они смогут объяснить мой вопрос более четко.

Итак, у нас есть два сценария A и B

В скрипте A -

from time import sleep

# will output a number every 1 second on the console
def Show(number, Function):    
    while(number < 5):
        sleep(1)            # Wait specified time
        number += 1         # Some random operation, here incrementing the number by 1

        print(number)       # On console
        Function(number)    # On widget

В скрипте B -

import A
import tkinter as tk

number = 0

root = tk.Tk()

# Function which will be passed as an argument
def Print(number):
    label = tk.Label(root, text=number)
    label.pack()

# Will be used for the after method [ OPTIONAL ]
def Delay(number, Print):
    root.after(5000, test.Show(number, Print))

# Below I recommend to comment either one of the button initializations, in order to test each ways

# Using sleep method
button = tk.Button(root, text='Start', command=lambda: A.Show(number, Print))

                             #OR

# Using after method
button = tk.Button(root, text='Start', command=lambda: Delay(number, Print))


button.pack()

tk.mainloop()

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

ОБНОВЛЕНИЕ: это не настоящая проблема, это простоупрощенная версия моей актуальной проблемы. Так что не думайте, что я пытаюсь усложнить этот код. Как я тренирую классификатор с обученным NN, так вывод выводится на каждой итерации на консоли. Поэтому я хочу добиться того, чтобы выходные данные печатались на текстовом виджете одновременно и во время текущего цикла.

ОБНОВЛЕНИЕ 2: Этонаконец-то работает так, как я хотел. Ответ заключается в использовании потоков, как описано Майком: D

1 Ответ

1 голос
/ 14 октября 2019

sleep() и tkinter не ладят. Также не while. Проблема с sleep и while заключается в том, что они блокируют основной цикл до тех пор, пока они не будут завершены, и, таким образом, ничего не обновляется в вашем графическом интерфейсе, пока они не завершатся. Тем не менее, я думаю, что вы делаете этот код более сложным, чем нужно. У вас есть 2 функции для чего-то, что можно просто сделать в одном, и вы передаете функции в функции. Это намного сложнее, чем нужно.

Вы также упаковываете новую этикетку каждый раз, когда вызывается печать. Пожалуйста, попробуйте придерживаться стандарта PEP8 для обозначения вашей функции. all_low_with_underscores для стандартных функций и переменных.

Метод after() специально разработан для обработки временных событий в tkinter и в основном используется для замены sleep в графическом интерфейсе.

Вот ваш кодупрощенный и использующий after():

import tkinter as tk


def delay_and_print():
    global number
    if number < 5:
        print(number)
        label.config(text=number)
        number += 1
        root.after(1000, delay_and_print)


root = tk.Tk()
number = 0
tk.Button(root, text='Start', command=delay_and_print).pack()
label = tk.Label(root, text='')
label.pack()
root.mainloop()

Вот пример использования потоков:

import tkinter as tk
import threading
from time import sleep


def delay_and_print():
    global number
    if number < 100:
        print(number)
        label.config(text=number)
        number += 1
        sleep(2)
        delay_and_print()


def start_thread():
    thread = threading.Thread(target=delay_and_print)
    thread.start()


def do_something():
    print('Something')


root = tk.Tk()
number = 0
tk.Button(root, text='Start', command=start_thread).pack()
tk.Button(root, text='some other button to test if app is responsive while loop is going!', command=do_something).pack()
label = tk.Label(root, text='')
label.pack()
root.mainloop()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...