from pythoncom import PumpWaitingMessages
import pyHook, threading
import tkinter as tk
threadsRun = 1
token = 0
def pas():
while threadsRun:
pass
def listen(startButton):
"""Listens for keystrokes"""
def OnKeyboardEvent(event):
"""A key was pressed"""
global threadsRun
if event.Key == "R":
startButton.config(relief=tk.RAISED, state=tk.NORMAL, text="Start")
threadsRun = 0
return True
hm = pyHook.HookManager()
hm.KeyDown = OnKeyboardEvent
hm.HookKeyboard()
while threadsRun:
PumpWaitingMessages()
else:
hm.UnhookKeyboard()
def simplegui():
def threadmaker():
"""Starts threads running listen() and pas()"""
startButton.config(relief=tk.SUNKEN, state=tk.DISABLED, text="r=stop listening")
global token, threadsRun
threadsRun = 1
token += 1
t1 = threading.Thread(target=pas, name='pas{}'.format(token))
t2 = threading.Thread(target=listen, args=(startButton,), name='listen{}'.format(token))
t1.start()
t2.start()
def destroy():
"""exit program"""
global threadsRun
threadsRun = 0
root.destroy()
startButton = tk.Button(root, text="Start", command=threadmaker, height=10, width=20)
startButton.grid(row=1, column=0)
quitButton = tk.Button(root, text="Quit", command=destroy, height=10, width=20)
quitButton.grid(row=1, column=1)
root = tk.Tk()
simplegui()
root.mainloop()
代码说明:
simplegui()
创建两个线程来运行
pas()
和
listen()
同时点。
listen()
等待键盘按下(仅r
执行任何操作:退出两个线程/函数)。
pas()
除了重现bug之外什么都不做。
问题描述:
单击开始后,按键盘上的任何按钮都可能导致tkinter
停止响应。
〜{3/3'时间r
将按预期运行。
我正在使用Spyder IDE(python 3.5)。
一些观察:
使用print语句,程序将在崩溃前进入while threadsRun
listen()
循环,但未到达OnKeyboardEvent()
print 语句。
可以在按键前等待很长时间,它可能会冻结。
按下启动后可以立即按键,它可以按预期运行。
删除t1 = ...
和t1.start()
行可以使程序无错运行
或者,删除所有tkinter
代码允许程序无错运行
捣乱一堆钥匙一下子冻结了它
如果我在while threadsRun
循环中放置一个print语句,r
将很少有效。
我在其他帖子中读过,tkinter
不是线程安全的,并且使用队列。但我不明白怎么做。我也想也许别的东西是错的,因为它有时会起作用。 https://www.reddit.com/r/learnpython/comments/1v5v3r/tkinter_uis_toplevel_freezes_on_windows_machine/
非常感谢阅读。
答案 0 :(得分:0)
我设法用于线程和队列的一次尝试如下(用多个伪代码条目替换使用过的代码)
该类充当会话监视程序并使用sql命令收集登录用户,然后使用线程进行位置检测(geoip)
import Tkinter as tk
import ttk
import Queue
import Locator
class SessionWatchdog(ttk.Frame):
"""
Class to monitor active Sessions including Location in a threaded environment
"""
__queue = None
__sql = None
def __init__(self, *args, **kwargs):
#...
# Create the Queue
self.__queue = Queue.Queue()
def inqueue(self):
""" Handle Input from watchdog worker Thread """
if self.__queue.empty():
return
while self.__queue.qsize():
"""
Use
try:
self.__queue.get()
finally:
self.__queue.task_done()
to retrieve data from the queue
"""
pass
def gather_data(self, queue):
"""
Retrieve online users and locate them
"""
if self.__sql:
threads = []
# gather data via sql
# ....
# ....
for data in sql_result:
thread = Locator(queue, data)
threads.append(thread)
thread.start()
for thread in threads:
thread.join()
填充队列的定位器:
import threading
import Queue
class Locator(threading.Thread):
"""
docstring
"""
__base_url = "http://freegeoip.net/json/{}"
def __init__(self, queue, user_information):
threading.Thread.__init__(self)
self.queue = queue
self.user_information = user_information
def run(self):
""" add location information to data (self.user_information)
to improve performance, we put the localization in single threads.
"""
located_user = []
# locate the user in a function, NOT method!
self.queue.put(located_user, False)