Python/QT/线程

问题描述

  • IDE: PyCharm Community Edition 2020.3 / PyCharm Community Edition 2020.2.1

  • Python Interpreter: Location(venv) + Base interpreter(Python39)

  • OS: Win10

  • PyQt5+PySide6 GUI开发,在按下一个QPushButton后同时执行:

  • 鼠标自动按下Steam游戏界面的播放按钮,间隔一段时间,再按下暂停按钮
  • 进行按键检测(上下左右)
  • from pynput.keyboard import Listener
    from time import sleep
    import pyautogui as pg
    import speech
    import threading
    class MainWindow(QMainWindow):
        def __init__(self):
            widgets.btn_startvr.clicked.connect(self.proc_buttonClick(self):)
        def proc_buttonClick(self):
            # GET BUTTON CLICKED
            btn = self.sender()
            btnName = btn.objectName()
            # StartVR Button CLICK
            def startVR():
                print('子线程startVR:{}'.format(threading.current_thread().name))
                def pgClick(xx, yy):
                    pg.click(xx, yy, button='left')
                def report():                
                    speech.say("请报告")
                x = widgets.spinBox_x.value()
                y = widgets.spinBox_y.value()
                pgClick(x, y)  # 开始
                sleep(160)  # 间隔 160s
                pgClick(x, y)  # 暂停
                report()
                pgClick(x, y)  # 开始
                sleep(127)  # 间隔 127s
            # Keyboard Listener
            def on_release(key):
                 print('子线程listenKey:{}'.format(threading.current_thread().name))
                # print('{0} release'.format(key))
                k = '{0}'.format(key)
                if k == "Key.up":
                    print("up")
                elif k == "Key.left":
                    print("left")
                elif k == "Key.down":
                    print("down")
                elif k == "Key.right":
                    print("right")
                elif k == "Key.caps_lock":
                    print('Stop this thread!')
                    return False
                else:
            if btnName == "btn_startvr":
                task = threading.Thread(target=startVR)
                task.start()
                k = Listener(on_release=on_release)
                k.start()
                # task.join()  # 加join后会更快挂掉
                # k.join() # 加join后会更快挂掉
    

    当只有python界面运行时能跑通,加上Steam+VR游戏界面运行时,会在中途退出,pycharm报错:Process finished with exit code -1073741819 (0xC0000005)。
    查了相关的解决方法:方法汇总1方法汇总2,觉得不对口。因为去掉按键检测线程,能跑通,所以应该是线程有问题

    from pynput.keyboard import Listener
    from time import sleep
    import pyautogui as pg
    import speech
    import threading
    class MainWindow(QMainWindow):
        def __init__(self):
             # 去掉GUI控件的焦点,才能检测上下左右键
            self.setChildrenFocusPolicy(Qt.NoFocus) 
            widgets.btn_startvr.clicked.connect(self.startvr_buttonClick(self):)
         # startvr Button CLICK
         def startvr_buttonClick(self):
            self.vr_thread = VRThread()
            self.vr_thread.start()
         def setChildrenFocusPolicy(self, policy):
            def recursiveSetChildFocusPolicy(parentQWidget):
                for childQWidget in parentQWidget.findChildren(QWidget):
                    childQWidget.setFocusPolicy(policy)
                    recursiveSetChildFocusPolicy(childQWidget)
            recursiveSetChildFocusPolicy(self)      
         def keyPressEvent(self, eventQKeyEvent):
            key = eventQKeyEvent.key()
            if key == Qt.Key_Up:
                print('up')
            elif key == Qt.Key_Left:
                print('left')
            elif key == Qt.Key_Down:
                print('down')
            elif key == Qt.Key_Right:
                print('right')
            else:
    class VRThread(QThread):
        def __init__(self):
            super(VRThread, self).__init__()
            self.quit_flag = False
        def __del__(self):
            self.wait()
        def run(self):
            while True:
                if not self.quit_flag:
                    self.doVR()
                    self.quit_flag = True
                else:
                    break
            # self.quit()
            # self.wait()
        def doVR(self):
            print('子线程doVR:{}'.format(threading.current_thread().name))
            def pgClick(xx, yy):
                pg.click(xx, yy, button='left')
            def report():                 
                #在游戏界面点击后,python窗口不再是最前面的窗口,失去Focus后,将无法检测箭头按键
                #实现自动切换窗口(模拟手动alt+tab切换窗口的效果)
                g.keyDown('alt')
                sleep(.2)
                pg.press('tab')
                sleep(.2)
                pg.keyUp('alt')
                speech.say("请报告")
            x = widgets.spinBox_x.value()
            y = widgets.spinBox_y.value()
            pgClick(x, y)  # 开始
            sleep(160)  # 间隔 160s
            pgClick(x, y)  # 暂停
            report()
            pgClick(x, y)  # 开始
            sleep(127)  # 间隔 127s
    

    颁发有效信息奖(排名不分先后)

    了解进程/线程