Linuxにてpynputとthreadingを組み合わせるとフリーズします
解決したいこと
Pythonでpynputのキー入力をON/OFFする機構を
検討しているのですが、Linux上でthreadingを使用すると
処理がフリーズします。
解決方法をご教授頂けますでしょうか?
プログラムの説明と発生している問題
tkinterのウィンドウにて
ボタンでpynputの入力受付のON/OFFを行い、
ラベルにて正常にプログラムが動くことの確認として
1秒毎にカウントアップするプログラムです。
コード1の場合はthreadingにてカウントアップを行い、
コード2の場合はtkinterのafter()メソッドにてカウントアップを行っています。
Windows上ではコード1、コード2ともに
正常にpynputの入力受付のON/OFFが行えるのですが、
Linux上ではコード1だとkey_disable()内の
self.key_listener.stop()のタイミングで
プログラムがフリーズします。
コード2はLinux上でも正常に動作するのですが、最終的にはthreadingを用いて描画とは別で動かしたい処理があるため、解決策を模索しております。
コード1
import tkinter as tk
from pynput.keyboard import Key, Listener
import time
from threading import Thread
class Application(tk.Frame):
def __init__(self, master = None):
super().__init__(master)
self.master.title("ボタンの作成") # ウィンドウタイトル
self.master.geometry("200x100") # ウィンドウサイズ(幅x高さ)
self.flag = False
self.button_text = tk.StringVar()
self.label_text = tk.StringVar()
self.button_text.set("OFF")
self.counter = 0
self.label_text.set(str(self.counter))
self.key_listener = None
self.thread = Thread(target=self.counter_thread, args=())
self.thread_flag = True
self.thread.start()
self.master.protocol("WM_DELETE_WINDOW", self.exit)
#--------------------------------------------------------
# ボタンの作成
self.button = tk.Button(self.master,
textvariable=self.button_text,
command = self.button_click
)
self.button.grid(column='0', row='0', padx='5', pady='5', sticky='ew')
self.label = tk.Label(self.master, textvariable=self.label_text)
self.label.grid(column='1', row='0', padx='5', pady='5', sticky='ew')
#--------------------------------------------------------
def button_click(self):
if self.flag == True:
print("Key入力OFF")
self.key_disable()
else:
print("Key入力ON")
self.key_enable()
def counter_inc(self):
self.counter += 1
self.label_text.set(str(self.counter))
def counter_thread(self):
while self.thread_flag:
self.counter_inc()
time.sleep(1)
def key_enable(self):
self.flag = True
if self.key_listener == None:
self.button_text.set("ON")
self.key_listener = Listener(on_press=self.on_press,
on_release=self.on_release)
self.key_listener.start()
def key_disable(self):
self.flag = False
if self.key_listener != None:
self.button_text.set("OFF")
self.key_listener.stop()
self.key_listener = None
def on_press(self, key):
print('{0} pressed'.format(key))
def on_release(self, key):
print('{0} released'.format(key))
def exit(self):
self.thread_flag = False
self.thread.join()
self.key_disable()
self.master.destroy()
if __name__ == "__main__":
root = tk.Tk()
app = Application(master = root)
app.key_enable()
app.mainloop()
コード2
import tkinter as tk
from pynput.keyboard import Key, Listener
import time
from threading import Thread
class Application(tk.Frame):
def __init__(self, master = None):
super().__init__(master)
self.master.title("ボタンの作成") # ウィンドウタイトル
self.master.geometry("200x100") # ウィンドウサイズ(幅x高さ)
self.flag = False
self.button_text = tk.StringVar()
self.label_text = tk.StringVar()
self.button_text.set("OFF")
self.counter = 0
self.label_text.set(str(self.counter))
self.key_listener = None
self.master.protocol("WM_DELETE_WINDOW", self.exit)
#--------------------------------------------------------
# ボタンの作成
self.button = tk.Button(self.master,
textvariable=self.button_text,
command = self.button_click
)
self.button.grid(column='0', row='0', padx='5', pady='5', sticky='ew')
self.label = tk.Label(self.master, textvariable=self.label_text)
self.label.grid(column='1', row='0', padx='5', pady='5', sticky='ew')
self.master.after(1000, self.counter_after)
#--------------------------------------------------------
def button_click(self):
if self.flag == True:
print("Key入力OFF")
self.key_disable()
else:
print("Key入力ON")
self.key_enable()
def counter_inc(self):
self.counter += 1
self.label_text.set(str(self.counter))
def counter_thread(self):
while self.thread_flag:
self.counter_inc()
time.sleep(1)
def counter_after(self):
self.counter_inc()
self.master.after(1000, self.counter_after)
def key_enable(self):
self.flag = True
if self.key_listener == None:
self.button_text.set("ON")
self.key_listener = Listener(on_press=self.on_press,
on_release=self.on_release)
self.key_listener.start()
def key_disable(self):
self.flag = False
if self.key_listener != None:
self.button_text.set("OFF")
self.key_listener.stop()
self.key_listener = None
def on_press(self, key):
print('{0} pressed'.format(key))
def on_release(self, key):
print('{0} released'.format(key))
def exit(self):
#self.thread_flag = False
#self.thread.join()
self.key_disable()
self.master.destroy()
if __name__ == "__main__":
root = tk.Tk()
app = Application(master = root)
app.key_enable()
app.mainloop()