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:
                pass

       
        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:
            pass

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
        ……       

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

了解进程/线程
进程/线程区别
PyQt: multiprocessing or threading?
PyQt5+QThread
模拟alt+tab按键/来源
模拟alt+tab按键/实现

你可能感兴趣的:(Python/QT/线程)