如何让 TkInter GUI(不是 shell 提示符)监听来自 /dev/stdin 的输入
Posted
技术标签:
【中文标题】如何让 TkInter GUI(不是 shell 提示符)监听来自 /dev/stdin 的输入【英文标题】:How to get a TkInter GUI (not a shell prompt) to Listen for Input from /dev/stdin 【发布时间】:2017-11-26 23:59:13 【问题描述】:我正在编写一个带有 GUI 的 Python 程序,它侦听正在呈现的 RFID 令牌(使用模拟键盘输入的 USB 阅读器)。我遇到的问题是,只有在我启动脚本的终端具有焦点时,才会监听键盘/RFID 输入并采取行动。
如果 GUI 被聚焦,所有输入都会被忽略,但是当终端有焦点时,它可以正常工作,甚至会向 GUI 和 shell 发送更新。我试过在 GUI 上画一个文本输入框,但是没用。
我想知道这是否与它需要如何使用多个线程、队列甚至进程有关 - 谁能帮助我更好地理解它?
代码如下,提前致谢!
#!/usr/bin/env python3
import sys
import mysqldb
try:
# python 2
import Tkinter as tk
import ttk
except ImportError:
# python 3
import tkinter as tk
from tkinter import ttk
from threading import Thread
class Fullscreen_Window:
def __init__(self):
self.tk = tk.Tk()
self.tk.title("Listening for RFID token...")
self.frame = tk.Frame(self.tk)
self.frame.pack()
self.tk.attributes('-zoomed', True)
self.state = False
self.tk.bind("<F11>", self.toggle_fullscreen)
self.tk.bind("<Escape>", self.end_fullscreen)
self.tk.config(cursor="none")
t = Thread(target=self.listen_rfid)
t.daemon = True
t.start()
def toggle_fullscreen(self, event=None):
self.state = not self.state # Just toggling the boolean
self.tk.attributes("-fullscreen", self.state)
return "break"
def end_fullscreen(self, event=None):
self.state = False
self.tk.attributes("-fullscreen", False)
return "break"
def listen_rfid(self):
dbHost = 'localhost'
dbName = 'python'
dbUser = 'python'
dbPass = 'PASSWORD'
dbConnection = MySQLdb.connect(host=dbHost, user=dbUser, passwd=dbPass, db=dbName)
cur = dbConnection.cursor(MySQLdb.cursors.DictCursor)
with open('/dev/stdin', 'r') as tty:
while True:
RFID_input = tty.readline().rstrip()
cur.execute("SELECT * FROM access_list WHERE rfid_code = '%s'" % (RFID_input))
if cur.rowcount != 1:
print("ACCESS DENIED")
ttk.Label(self.tk, text="ACCESS DENIED").pack()
else:
user_info = cur.fetchone()
print("Welcome %s!!" % (user_info['name']))
ttk.Label(self.tk, text="Welcome %s!!" % (user_info['name'])).pack()
tty.close()
if __name__ == '__main__':
w = Fullscreen_Window()
w.tk.mainloop()
【问题讨论】:
【参考方案1】:在头疼之后,我再次找到this thread 并正确地重新阅读它,然后意识到它包含了我想要的答案,尽管我需要做一些工作。
我的listen_rfid
函数现在看起来像下面的代码。希望它对遇到我的问题的人有用!
关键是查看/dev/input/by-id
并找到您的设备,会有一个符号链接(至少在我的 Raspbian 安装中)指向更优雅的东西,例如,在我的情况下,“/event0
” - 如以下)。然后就可以使用 python-evdev 来读取了。
如果你没有python-evdev,只需使用sudo pip install evdev
安装即可
这是工作代码:
def listen_rfid(self):
dbHost = 'localhost'
dbName = 'python'
dbUser = 'python'
dbPass = 'PASSWORD'
dbConnection = MySQLdb.connect(host=dbHost, user=dbUser, passwd=dbPass, db=dbName) # ToDo: This needs some error handling for if MySQL has gone away, and reconnect.
cur = dbConnection.cursor(MySQLdb.cursors.DictCursor)
from evdev import InputDevice
from select import select
keys = "X^1234567890XXXXqwertzuiopXXXXasdfghjklXXXXXyxcvbnmXXXXXXXXXXXXXXXXXXXXXXX"
dev = InputDevice('/dev/input/event0')
rfid_presented = ""
while True:
r,w,x = select([dev], [], [])
for event in dev.read():
if event.type==1 and event.value==1:
if event.code==28:
#print("RFID: " + str(rfid_presented))
cur.execute("SELECT * FROM access_list WHERE rfid_code = '%s'" % (rfid_presented))
if cur.rowcount != 1:
#print("ACCESS DENIED")
ttk.Label(self.tk, text="ACCESS DENIED").pack()
else:
user_info = cur.fetchone()
#print("Welcome %s!!" % (user_info['name']))
ttk.Label(self.tk, text="Welcome %s!!" % (user_info['name'])).pack()
rfid_presented = ""
else:
rfid_presented += keys[ event.code ]
【讨论】:
以上是关于如何让 TkInter GUI(不是 shell 提示符)监听来自 /dev/stdin 的输入的主要内容,如果未能解决你的问题,请参考以下文章
如何让 Matplotlib 图形在 Tkinter GUI 中正确滚动+调整大小