如果我的NumLk打开或关闭,我的计算机没有办法告诉我,所以我试图在我的系统中添加一个图标,该图标将根据我的NumLk的状态而改变。我的计算机开启时,此.py将始终运行。
到目前为止,我能够混合3个代码,并且我能够在系统托盘中显示图标,但是当NumLk的状态发生变化时,它不会更新。实际上,如果我按两次NumLk,我仍然会得到相同的图标(on
一个),我收到此错误:
QCoreApplication::exec: The event loop is already running
File "\systray_icon_NumLk_on_off.py", line 21, in on_key_press
main(on)
File "\systray_icon_NumLk_on_off.py", line 46, in main
sys.exit(app.exec_())
SystemExit: -1
我的代码可能不是最好的方法,所以欢迎任何替代方案!这是我到目前为止所得到的:
#####get the state of NumLk key
from win32api import GetKeyState
from win32con import VK_NUMLOCK
#how to use: print(GetKeyState(VK_NUMLOCK))
#source: http://stackoverflow.com/questions/21160100/python-3-x-getting-the-state-of-caps-lock-num-lock-scroll-lock-on-windows
#####Detect if NumLk is pressed
import pyglet
from pyglet.window import key
window = pyglet.window.Window()
#source: http://stackoverflow.com/questions/28324372/detecting-a-numlock-capslock-scrlock-keypress-keyup-in-python
on=r'on.png'
off=r'off.png'
@window.event
def on_key_press(symbol, modifiers):
if symbol == key.NUMLOCK:
if GetKeyState(VK_NUMLOCK):
#print(GetKeyState(VK_NUMLOCK))#should be 0 and 1 but
main(on)
else:
main(off)
@window.event
def on_draw():
window.clear()
### display icon in systray
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
#source: http://stackoverflow.com/questions/893984/pyqt-show-menu-in-a-system-tray-application - add answer PyQt5
class SystemTrayIcon(QtWidgets.QSystemTrayIcon):
def __init__(self, icon, parent=None):
QtWidgets.QSystemTrayIcon.__init__(self, icon, parent)
menu = QtWidgets.QMenu(parent)
exitAction = menu.addAction("Exit")
self.setContextMenu(menu)
def main(image):
app = QtWidgets.QApplication(sys.argv)
w = QtWidgets.QWidget()
trayIcon = SystemTrayIcon(QtGui.QIcon(image), w)
trayIcon.show()
sys.exit(app.exec_())
if __name__ == '__main__':
pyglet.app.run()
答案 0 :(得分:1)
QCoreApplication::exec: The event loop is already running
的原因实际上是因为您尝试两次启动app.run()
。 Qt会注意到已经有一个实例正在运行并抛出此异常。相反,您想要做的只是交换已经运行的实例中的图标。
如果你问我,这里的主要问题实际上是图书馆的混合来解决一项任务 相反,两个任务,但使用Qt5的图形部分是很好的。
你开始使用Pyglet的方式是错误的。
Pyglet旨在成为一个功能强大且高效的图形库,您可以在其上构建图形引擎。例如,如果你正在制作游戏或视频播放器等等。
你使用win32api的方式也是错误的,因为你在一个图形窗口中使用它,只在该窗口内按下一个键时检查该值。
现在,如果您将win32api
代码移动到一个线程(确切地说是一个QtThread),无论您是否在图形窗口内按下了键,都可以检查状态。
import sys
import win32api
import win32con
from PyQt5 import QtCore, QtGui, QtWidgets
from threading import Thread, enumerate
from time import sleep
class SystemTrayIcon(QtWidgets.QSystemTrayIcon):
def __init__(self, icon, parent=None):
QtWidgets.QSystemTrayIcon.__init__(self, icon, parent)
menu = QtWidgets.QMenu(parent)
exitAction = menu.addAction("Exit")
exitAction.setShortcut('Ctrl+Q')
exitAction.setStatusTip('Exit application')
exitAction.triggered.connect(QtWidgets.qApp.quit)
self.setContextMenu(menu)
class KeyCheck(QtCore.QThread):
def __init__(self, mainWindow):
QtCore.QThread.__init__(self)
self.mainWindow = mainWindow
def run(self):
main = None
for t in enumerate():
if t.name == 'MainThread':
main = t
break
while main and main.isAlive():
x = win32api.GetAsyncKeyState(win32con.VK_NUMLOCK)
## Now, GetAsyncKeyState returns three values,
## 0 == No change since last time
## -3000 / 1 == State changed
##
## Either you use the positive and negative values to figure out which state you're at.
## Or you just swap it, but if you just swap it you need to get the startup-state correct.
if x == 1:
self.mainWindow.swap()
elif x < 0:
self.mainWindow.swap()
sleep(0.25)
class GUI():
def __init__(self):
self.app = QtWidgets.QApplication(sys.argv)
self.state = True
w = QtWidgets.QWidget()
self.modes = {
True : SystemTrayIcon(QtGui.QIcon('on.png'), w),
False : SystemTrayIcon(QtGui.QIcon('off.png'), w)
}
self.refresh()
keyChecker = KeyCheck(self)
keyChecker.start()
sys.exit(self.app.exec_())
def swap(self, state=None):
if state is not None:
self.state = state
else:
if self.state:
self.state = False
else:
self.state = True
self.refresh()
def refresh(self):
for mode in self.modes:
if self.state == mode:
self.modes[mode].show()
else:
self.modes[mode].hide()
GUI()
请注意,我不经常进行Qt编程(每4年左右) 因此,这个代码是最好的错误。您必须按 Ctrl + C +按菜单中的“退出”才能停止。
老实说,我不想花更多的时间和精力学习如何在Qt中管理线程或如何正确退出应用程序,这不是我的专家领域。但是这将为您提供一个粗略的工作示例,说明如何交换下角的图标,而不是尝试重新设置您所做的main()
循环。