2014-01-02 2 views
0

Я делаю утилиту для удобного управления режимами использования ноутбуков-планшетов (т. Е. Для легкого переключения между режимами ноутбука, режима записи стилуса и т. Д.). , Я пытаюсь использовать Python threading для процесса, который постоянно контролирует определенный статус в цикле и, если этот статус изменяется, он выполняет некоторые действия. Этот мониторинг должен запускаться одновременно с графическим интерфейсом PyQt, однако GUI никогда не запускается, и я не знаю, почему. Я бы оценил некоторые рекомендации по этому вопросу.Как предотвратить поток Python от остановки PyQt GUI

В коде используется метод stylusProximityControl. Код выглядит следующим образом:

import os 
import sys 
import subprocess 
import threading 
import time 
from PyQt4 import QtGui 
import logging 

# logging 
logger = logging.getLogger(__name__) 
logging.basicConfig() 
logger.level = logging.INFO 

class interface(QtGui.QWidget): 
    def __init__(self): 
     super(interface, self).__init__() 
     logger.info("running spin") 
     # engage stylus proximity control 
     self.stylusProximityControlOn() 
     # create buttons 
     buttonsList = [] 
     # button: tablet mode 
     buttonModeTablet = QtGui.QPushButton('tablet mode', self) 
     buttonModeTablet.clicked.connect(self.engageModeTablet) 
     buttonsList.append(buttonModeTablet) 
     # button: laptop mode 
     buttonModeLaptop = QtGui.QPushButton('laptop mode', self) 
     buttonModeLaptop.clicked.connect(self.engageModeLaptop) 
     buttonsList.append(buttonModeLaptop) 
     # button: left 
     buttonLeft = QtGui.QPushButton('left', self) 
     buttonLeft.clicked.connect(self.engageLeft) 
     buttonsList.append(buttonLeft) 
     # button: right 
     buttonRight = QtGui.QPushButton('right', self) 
     buttonRight.clicked.connect(self.engageRight) 
     buttonsList.append(buttonRight) 
     # button: inverted 
     buttonInverted = QtGui.QPushButton('inverted', self) 
     buttonInverted.clicked.connect(self.engageInverted) 
     buttonsList.append(buttonInverted) 
     # button: normal 
     buttonNormal = QtGui.QPushButton('normal', self) 
     buttonNormal.clicked.connect(self.engageNormal) 
     buttonsList.append(buttonNormal) 
     # button: touchscreen on 
     buttonTouchscreenOn = QtGui.QPushButton('touchscreen on', self) 
     buttonTouchscreenOn.clicked.connect(self.engageTouchscreenOn) 
     buttonsList.append(buttonTouchscreenOn) 
     # button: touchscreen off 
     buttonTouchscreenOff = QtGui.QPushButton('touchscreen off', self) 
     buttonTouchscreenOff.clicked.connect(self.engageTouchscreenOff) 
     buttonsList.append(buttonTouchscreenOff) 
     # button: touchpad on 
     buttonTouchpadOn = QtGui.QPushButton('touchpad on', self) 
     buttonTouchpadOn.clicked.connect(self.engageTouchpadOn) 
     buttonsList.append(buttonTouchpadOn) 
     # button: touchpad off 
     buttonTouchpadOff = QtGui.QPushButton('touchpad off', self) 
     buttonTouchpadOff.clicked.connect(self.engageTouchpadOff) 
     buttonsList.append(buttonTouchpadOff) 
     # button: nipple on 
     buttonNippleOn = QtGui.QPushButton('nipple on', self) 
     buttonNippleOn.clicked.connect(self.engageNippleOn) 
     buttonsList.append(buttonNippleOn) 
     # button: nipple off 
     buttonNippleOff = QtGui.QPushButton('nipple off', self) 
     buttonNippleOff.clicked.connect(self.engageNippleOff) 
     buttonsList.append(buttonNippleOff) 
     # button: stylus proximity on 
     buttonStylusProximityControlOn = QtGui.QPushButton('stylus proximity on', self) 
     buttonStylusProximityControlOn.clicked.connect(self.engageStylusProximityControlOn) 
     buttonsList.append(buttonStylusProximityControlOn) 
     # button: stylus proximity off 
     buttonStylusProximityControlOff = QtGui.QPushButton('stylus proximity off', self) 
     buttonStylusProximityControlOff.clicked.connect(self.engageStylusProximityControlOff) 
     buttonsList.append(buttonStylusProximityControlOff) 
     # set button dimensions 
     buttonsWidth=150 
     buttonsHeight=60 
     for button in buttonsList: 
      button.setFixedSize(buttonsWidth, buttonsHeight) 
     # set layout 
     vbox = QtGui.QVBoxLayout() 
     vbox.addStretch(1) 
     for button in buttonsList: 
      vbox.addWidget(button) 
      vbox.addStretch(1) 
     self.setLayout(vbox) 
     # window 
     self.setGeometry(200, 200, 150, 100) 
     self.setWindowTitle('spin') 
     self.show() 
    def displayLeft(self): 
     logger.info("changing display to left") 
     os.system('xrandr -o left') 
    def displayRight(self): 
     logger.info("changing display to right") 
     os.system('xrandr -o right') 
    def displayInverted(self): 
     logger.info("changing display to inverted") 
     os.system('xrandr -o inverted') 
    def displayNormal(self): 
     logger.info("changing display to normal") 
     os.system('xrandr -o normal') 
    def touchscreenLeft(self): 
     logger.info("changing touchscreen to left") 
     os.system('xinput set-prop "ELAN Touchscreen" "Coordinate Transformation Matrix" 0 -1 1 1 0 0 0 0 1') 
    def touchscreenRight(self): 
     logger.info("changing touchscreen to right") 
     os.system('xinput set-prop "ELAN Touchscreen" "Coordinate Transformation Matrix" 0 1 0 -1 0 1 0 0 1') 
    def touchscreenInverted(self): 
     logger.info("changing touchscreen to inverted") 
     os.system('xinput set-prop "ELAN Touchscreen" "Coordinate Transformation Matrix" -1 0 1 0 -1 1 0 0 1') 
    def touchscreenNormal(self): 
     logger.info("changing touchscreen to normal") 
     os.system('xinput set-prop "ELAN Touchscreen" "Coordinate Transformation Matrix" 1 0 0 0 1 0 0 0 1') 
    def touchscreenOn(self): 
     logger.info("changing touchscreen to on") 
     os.system('xinput enable "ELAN Touchscreen"') 
    def touchscreenOff(self): 
     logger.info("changing touchscreen to off") 
     os.system('xinput disable "ELAN Touchscreen"') 
    def touchpadOn(self): 
     logger.info("changing touchpad to on") 
     os.system('xinput enable "SynPS/2 Synaptics TouchPad"') 
    def touchpadOff(self): 
     logger.info("changing touchpad to off") 
     os.system('xinput disable "SynPS/2 Synaptics TouchPad"') 
    def nippleOn(self): 
     logger.info("changing nipple to on") 
     os.system('xinput enable "TPPS/2 IBM TrackPoint"') 
    def nippleOff(self): 
     logger.info("changing nipple to off") 
     os.system('xinput disable "TPPS/2 IBM TrackPoint"') 
    def stylusProximityControl(self): 
     previousProximityStatus = None 
     while True: 
      proximityCommand = 'xinput query-state "Wacom ISDv4 EC Pen stylus" | grep Proximity | cut -d " " -f3 | cut -d "=" -f2' 
      proximityStatus = subprocess.check_output(proximityCommand, shell=True).lower().rstrip() 
      if (proximityStatus == "out") and (previousProximityStatus != "out"): 
       logger.info("stylus inactive") 
     self.touchscreenOn() 
      elif (proximityStatus == "in") and (previousProximityStatus != "in"): 
       logger.info("stylus active") 
     self.touchscreenOff() 
     previousProximityStatus = proximityStatus 
      time.sleep(0.25) 
    def stylusProximityControlOn(self): 
     logger.info("changing stylus proximity control to on") 
     self.thread1=threading.Thread(target=self.stylusProximityControl()).start() 
    def stylusProximityControlOff(self): 
     logger.info("changing stylus proximity control to off") 
     self.thread1.join() 
    def engageModeTablet(self): 
     logger.info("engaging mode tablet") 
     self.displayLeft() 
    self.touchscreenLeft() 
     self.touchscreenOff() 
     self.touchpadOff() 
     self.nippleOff() 
    def engageModeLaptop(self): 
     logger.info("engaging mode laptop") 
     self.displayNormal() 
     self.touchscreenNormal() 
     self.touchscreenOn() 
     self.touchpadOn() 
     self.nippleOn() 
    def engageLeft(self): 
     logger.info("engaging mode left") 
     self.displayLeft() 
     self.touchscreenLeft() 
    def engageRight(self): 
     logger.info("engaging mode right") 
     self.displayRight() 
     self.touchscreenRight() 
    def engageInverted(self): 
     logger.info("engaging mode inverted") 
     self.displayInverted() 
     self.touchscreenInverted() 
    def engageNormal(self): 
     logger.info("engaging mode normal") 
     self.displayNormal() 
     self.touchscreenNormal() 
    def engageTouchscreenOn(self): 
     self.touchscreenOn() 
    def engageTouchscreenOff(self): 
     self.touchscreenOff() 
    def engageTouchpadOn(self): 
     self.touchpadOn() 
    def engageTouchpadOff(self): 
     self.touchpadOff() 
    def engageNippleOn(self): 
     self.nippleOn() 
    def engageNippleOff(self): 
     self.nippleOff() 
    def engageStylusProximityControlOn(self): 
     self.stylusProximityControlOn() 
    def engageStylusProximityControlOff(self): 
     self.stylusProximityControlOff() 
def main(): 
    application = QtGui.QApplication(sys.argv) 
    interface1 = interface() 
    sys.exit(application.exec_()) 
if __name__ == '__main__': 
    main() 

EDIT: three_pineappleshighlighted ошибка в коде. Эта ошибка была устранена и код обновлен.

+0

Существуют ли исключения? Мне кажется, что строка 'buttonsList.append (StylusProximityControlOn)' (и аналогичная пара строк ниже для ее отключения) вызовет исключение, поскольку StylusProximityControlOn не определен. Вы предположительно хотели добавить 'buttonStylusProximityControlOn' (и подобное в строках ниже)? –

+0

Вы совершенно правы. Спасибо, что заметили это. Я изменил код. Исключений не было. Вы можете увидеть запуск GUI, просто комментируя команду '' 'self.stylusProximityControlOn()' '' в методе '' '__init__''''. – d3pd

ответ

1

Хорошо, наконец, нашли время для запуска кода. Простая ошибка (вы будете бить себя!)

Вам нужно изменить строку

self.thread1=threading.Thread(target=self.stylusProximityControl()).start() 

в

self.thread1=threading.Thread(target=self.stylusProximityControl).start() 

Примечание удаление скобок после stylusProximityControl. Вы эффективно просили ваш метод stylusProximityControl выполнить и вернуть метод, который будет указан в качестве цели, threading.Thread. Конечно, у вашего метода был while True, поэтому функция не возвращалась для вызова threading.Thread для запуска в новом потоке. Надеюсь, это имеет смысл для вас!

Это позволит вам пройти мимо вашей непосредственной проблемы, хотя вам нужно будет подумать об использовании thread.join (я не вижу, чтобы нить когда-либо включалась, потому что цикл никогда не останавливается). Вероятно, вы хотите, чтобы цикл while выполнялся только в цикле, в то время как некоторое логическое значение имеет значение True, чтобы он мог очистить подпроцесс и выйти из цикла после завершения программы.

В любом случае, удачи, и я надеюсь, что вы разместили онлайн-проект где-то (битбакет или аналогичный), потому что он выглядит полезным!

+0

Ах! Это хорошо видно. Спасибо за это! Я понимаю, что вы имеете в виду, когда пытаетесь присоединиться, когда процесс застревает в цикле. Непосредственное решение состоит в том, чтобы просто убить процесс, но я думаю, что правильная связь (например, очереди или каналы) должна быть реализована, чтобы контролировать состояние этого процесса мониторинга. Еще раз спасибо. – d3pd

+0

Ох - и я поместил утилиту (которая была сделана для использования на моей ThinkPad Yoga, но, возможно, для других устройств для планшетных ПК) [здесь] (https://github.com/wdbm/spin). Я скоро обновляю его с помощью функции контроля близости стилуса. – d3pd

0

Я продвинулся к решению с использованием multiprocessing.

Я сделал следующие изменения:

  • от этого: import threading
    • к этому: from multiprocessing import Process
  • от этого: self.thread1 = threading.Thread(target=self.stylusProximityControl()).start()
    • к этому: self.process1 = Process(target=self.stylusProximityControl().start()
  • от этого: self.thread1.join()
    • к этому: self.process1.join()

Моя проблема сейчас становится процесс многопроцессорной для управления сближением к концу, когда выбран «X» в окне. Это может потребовать как выполнения метода stylusProximityControlOff(), так и возможной модификации метода.

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