Найти - Пользователи
Полная версия: Не отлавливается нажатие клавиши при запущенном втором потоке. Tkinter\threading.
Начало » Python для экспертов » Не отлавливается нажатие клавиши при запущенном втором потоке. Tkinter\threading.
1 2 3
buddha
Вот сценарий:
import threading
import time
from tkinter import Tk
from tkinter import Label
 
TIMEOUT = 10  # Время в секундах, по истечении которго будет посылаться запрос на получение данных.
 
# Функция, которая будет обновлять данные.
def waiter(func):
    while True:
        time.sleep(TIMEOUT)
        func()
 
def main():
    root_widg = Tk()
    root_widg.title('Уведомление по неотвеченным вопросам')
    root_widg.geometry("{}x{}+0+0".format(root_widg.winfo_screenwidth(), root_widg.winfo_screenheight()))
    root_widg.attributes('-fullscreen', 1)
  
    label = Label(root_widg, justify='left', wraplength=root_widg.winfo_screenwidth() - 20)
    label.pack(expand='yes', fill='both')
 
    def output():
    # тут делаю запрос на сервер
    # получаю ответ
    # паршу ответ
    # и в зависимости от пришедших параметров конфигурирую label
    # например label.config(text="Успех", bg='#78207E', fg='#4FEDEE', font=('times', 20, 'bold')) 
  
    thread = threading.Thread(target=waiter, args=(output,))
    thread.start()
 
    def escape(event):
        root_widg.quit()
 
    def leave(event):
        root_widg.attributes('-fullscreen', 0)
 
    def enter(event):
        root_widg.attributes('-fullscreen', 1)
 
    root_widg.bind('<Escape>', escape)
    root_widg.bind('<Alt-F4>', escape)
    root_widg.bind('<FocusIn>', enter)
    root_widg.bind('<FocusOut>', leave)
 
    output()
    root_widg.mainloop()
 
 
if __name__ == '__main__':
    main()

Так вот когда запускаю, ни <Escape>, ни <Alt-F4> не срабатывают для главного окна.
Программа работает, но выход можно сделать только убив процесс в диспетчере.
Помогите оживить закрытие главного окна по нажатию клавиш.
4kpt
Не уверен, что threading будет дружить с tkinter. У tkinter существуют свои механизмы запуска дополнительного цикла обработки событий.

P.S. Никогда не испытывал связку threading и tkinter. Может кто пробовал, тот напишет более внятный ответ или механизм борьбы с Вашей проблемой.
buddha
Какой механизм? Через него можно через каждые 10 секунд запускать функцию output(), при этом чтобы отлавливание клавиш не отвалилось?
4kpt
Такие задачи себе не ставил. По-идее можно.
Сейчас попробую и отпишусь.
4kpt
Получилось. Ну и задачка…

P.S. Вопрос еще актуален?
buddha
да, актуально.

4kpt
Ну и задачка…
Пришлось поколдлвать? какие сложности? Я так просто тупо не знаю, почему так себя ведёт програмка.
Без потока всё работает, как часы. Просто необходимо обновление данных… Посему запилен поток.
4kpt
Будете смеяться. Все прозаично и просто. Никаких костылей :)
Ловите…
# -*- coding: utf-8 -*-
import Tkinter
import time
tm = time.time()
def call_passive(event):
    print u"Выполнен шаг процесса."
    # Будет запускаться 10 секунд через каждую секунду
    if time.time() - tm < 10:
        root.after(1000, call_passive, event)
def call_active(event):
    print u"Пассивное нажатие в процессе."
root = Tkinter.Tk()
root.geometry("400x400+100+100")
bt_free = Tkinter.Button(root, width=20, text="Свободно нажимаем")
bt_free.place(relx=0.5, rely=0.33, anchor="center")
bt_free.bind("<ButtonRelease-1>", call_active)
bt_proc = Tkinter.Button(root, width=20, text=u"Запускаем процесс")
bt_proc.place(relx=0.5, rely=0.66, anchor="center")
bt_proc.bind("<ButtonRelease-1>", call_passive)
root.mainloop()
Ну как?
buddha
Ага вижу, рекусия в методе after(). В гугле видел её, но не пробовал. Попробую поменять реализацию сценария. Отпишусь потом…
4kpt
По гуглю не искал, не знаю, но метод .after() в tkinter запускает параллельный поток событий. О нем я писал выше. Но при его применении с циклом происходило выполнение всех событий одновременно. Если же использовался модуль time, то имело место зависание основного потока. Оставалось только одно - рекурсия, чтобы не ваять цикл, который этот поток событий будет стопарить. В этом случае .after вызывает функцию, котора вызывает в отдельном потоке .after и так циклично. Получается все “по-феншую” :)
buddha
Ну, а что будет когда рекурсия достигнет своего предела?
>>> sys.getrecursionlimit()
1000

Надо , чтобы сценарий висел долго\постоянно.
Да и я так понял метод after() крайне похож на threading.Timer(). Т.е. проблема отлова нажатия клавиш клавиатуры остаётся…
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Powered by DjangoBB