2017-01-22 40 views
0

Мой компьютер не имеет способа сообщить мне, включен ли мой NumLk, поэтому я пытаюсь добавить значок в свой systray, который будет изменен в зависимости от состояние моего NumLk. Этот .py всегда будет работать, когда мой компьютер включен.Как отображать иконку в systray, отражающую состояние NumLk

До сих пор я мог смешивать 3 кода, и я могу отображать значок в systray, но он не обновляется при изменении состояния 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() 
+1

Почему чрезмерное использование библиотек? Qt может проверять нажатие клавиш так же, как Pyglet. Также win32api может также ... Так почему же спагетти-логика? – Torxed

ответ

1

Причина QCoreApplication::exec: The event loop is already running на самом деле, потому что вы пытаетесь начать app.run() дважды. Qt заметит, что уже запущен экземпляр и выбрасывает это исключение. Вместо этого то, что вы хотите сделать, это просто заменить значок в уже запущенном экземпляре.

Ваша основная проблема в том, что на самом деле это сочетание библиотек для решения одной задачи, если вы меня спросите.
Скорее всего две задачи, но с использованием Qt5 для графической части является прекрасным.

То, как вы используете Pyglet, неверно.
Pyglet предназначен для того, чтобы быть очень мощной и эффективной графической библиотекой, в которой вы строите графический движок на нем. Например, если вы делаете игру или видео-плеер или что-то еще.

То, как вы используете win32api, также неверно, потому что вы используете его в графическом окне, которое проверяет только значение, когда в этом окне нажата клавиша.

Теперь, если вы переместите свой код win32api в Thread (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(), который вы сделали.

+0

Большое спасибо @Torxed. Это именно то, что я искал. Спагетти-логика была потому, что я новичок в python и, таким образом, скопировал коды из несвязанных сообщений. Теперь, когда вы положили какой-то заказ, я просто должен идти по прямой дороге! Большое спасибо за ваше время! – Enora

+0

@ Енора Мое удовольствие. Я начал так же, как и вы, просто выхватывая код отсюда и там и сбивая их с толку в один кусок спагетти. Он работает как инструмент обучения - так что держите его. Желаем удачи в вашем приключении и хорошей работе, получив первый бит на работу. – Torxed

 Смежные вопросы

  • Нет связанных вопросов^_^