Страницы

Поиск по вопросам

воскресенье, 2 февраля 2020 г.

Как сделать постоянное обновление окна Tkinter? Как избежать подвисания на время ожидания ответа от сервера

#python #python_3x #tkinter


Всем привет! для обновления окна использую 

root.update()


Но если программа делает например запрос к серверу и долго не получает ответ- программа
подвисает на время ожидания ответа. Как этого избежать и сделать так, чтобы программа
была всегда активна? Спасибо!
пример кода:

root=tk.Tk()
def work ():
    requests.get(url)
    time.sleep(5)
work()
root.mainloop()

    


Ответы

Ответ 1



Никогда никогда не используйте time.sleep(5) внутри цикла событий -- это замораживает ваше GUI на ~5 секунд. Используйте root.after(5000, some_action), чтобы выполнить код через 5 секунд в Tkinter. Чтобы выполнить работу, которая требует не фиксированное время (такую как отправка/чтение данных из сети, используя requests.get()), следует либо вынести в фоновый поток (threading), либо встроить операции ввода/вывода в сам цикл событий (Widget.tk.createfilehandler()). Примеры кода по ссылкам можно посмотреть: Мультизадачность на Python: выполнить две долгие функции одновременно, не блокируя GUI Конкретно, вот пример для tkinter, который читает вывод из внешней команды (self.proc.stdout.readline()), не блокируя цикл событий: вариант с фоновым потоком вариант без потока с createfilehandler(). Вот полный пример кода, который запускает requests.get() в фоновом потоке и обновляет показ текущего времени каждые 100 миллисекунд, пока запрос не завершится: #!/usr/bin/env python3 import time import tkinter from datetime import datetime from queue import Empty, Queue from threading import Thread import requests def display_result(label, q): try: label['text'] = q.get(block=False) except Empty: # update time at 100ms boundary label.after(round(100 - (1000 * time.time()) % 100), display_result, label, q) label['text'] = str(datetime.now().strftime("%H:%M:%S.%f")[:-3]) def get_result(q): # blocking function q.put('ip=' + requests.get('https://httpbin.org/delay/3').json()['origin']) # get result in a background thread result_queue = Queue() Thread(target=get_result, args=[result_queue], daemon=True).start() # display result root = tkinter.Tk() label = tkinter.Label(font=(None, 100)) label.pack() display_result(label, result_queue) # center window root.eval('tk::PlaceWindow %s center' % root.winfo_pathname(root.winfo_id())) root.mainloop() Чтобы обновить надпись (tkinter.Label) из другого потока, самый безопасный метод это использовать queue.Queue, как показано выше (то есть обращаться к label, только из потока с root.mainloop(), который её создал). Но если показывать прогресс не нужно (надпись прежняя остаётся пока блокирующий запрос не завершится), то в простых случаях можно обратиться и из другого потока напрямую: #!/usr/bin/env python3 import tkinter from threading import Thread import requests def fetch(url, on_response): requests.get(url, hooks=dict(response=on_response)) # blocking function def on_response(response, **unused_kwargs): # NOTE: it is called from another thread label['text'] = response.json()['origin'] # get result in a background thread root = tkinter.Tk() label = tkinter.Label(font=(None, 100), text='no result yet') label.pack() url = 'https://httpbin.org/delay/3' Thread(target=fetch, args=[url, on_response], daemon=True).start() root.mainloop() Современная реализация tkinter модуля в CPython пытается поддерживать обращение к tkinter объектам из других потоков. К примеру, если не включены потоки в Tcl интерпретаторе, то mutex расставляются, чтобы только один поток имел доступ к Tcl интерпретатору одновременно. Если включены потоки (tkinter.Tcl().eval('info exists ::tcl_platform(threaded)') == '1'), то обращения к Tcl из других потоков в очередь автоматически внутри tkinter добавляются и выполняются, когда управление вернётся на поток, где запущен Tcl интерпретатор (see all the gory details). Возможны баги, поэтому при возникновении любых проблем, обычно проще использовать упрощённую модель: все обращения к GUI объектам только в GUI потоке производятся.

Комментариев нет:

Отправить комментарий