【问题标题】:Why does the PyQt Window crash whenever my function is ran为什么每次运行我的函数时 PyQt 窗口都会崩溃
【发布时间】:2021-10-01 10:11:55
【问题描述】:

我的代码是这样的

class MainWindow(QMainWindow):


    def __init__(self):
        super(MainWindow, self).__init__()
        self.setGeometry(400, 400, 600, 480)
        self.setWindowTitle("HBCheat")
        self.initUI()

    def initUI(self):
        self.label = QtWidgets.QLabel(self)
        self.label.setText("Reaction Cheat")
        self.label.move(10, 0)

        self.b1 = QtWidgets.QPushButton(self)
        self.b1.setText("Toggle: off")
        self.b1.move(10, 35)
        self.b1.clicked.connect(self.reaction_cheat)
    
    def click(self,x,y): 
        win32api.SetCursorPos((x,y))
        win32api.mouse_event(win32con.MOUSEEVENTF_LEFTDOWN,0,0)
        time.sleep(0.01) 
        win32api.mouse_event(win32con.MOUSEEVENTF_LEFTUP,0,0)
    
    def reaction_cheat(self):
        self.b1.setText("Toggle: on")
        while not keyboard.is_pressed('q'):
            try:
                if pyautogui.pixel(1298, 415)[1] == 219:
                    self.click(1298, 415)
            except:
                continue
        self.b1.setText("Toggle: off")

当我点击按钮“b1”时,它应该运行函数reaction_cheat。它确实如此。但问题是按钮的文本没有改变并且窗口崩溃。如果我按下按钮,它仍然可以按预期工作,但按钮文本不会改变。如果我要注释掉“while not keyboard.is_pressed('q'):”循环。它会改变按钮的文本并且函数会结束。

那么为什么 b1 的文本没有改变,窗口崩溃了。

此外,当我按 q 时,它不会阻止窗口崩溃。但它仍然会停止循环并停止函数运行。

【问题讨论】:

  • 按钮文本没有改变,因为它正在获取窗口的更新被 while 循环阻止,在 "self.b1.setText("Toggle: on")" 行之后添加 QApplication.processEvents (),这应该可以解决按钮文本不更新的问题。如果需要,可能值得创建一个单独的 QThread 或进程来处理 mouse_event 以避免阻塞 GUI。

标签: python python-3.x user-interface pyqt5


【解决方案1】:

问题是因为检查键 q 是否被按下或没有消耗大量时间阻塞事件循环的逻辑。

一种可能的解决方案是使用线程,但另一种解决方案是使用 add_hotkey 函数,该函数允许使用回调避免使用 while 循环。您还应该避免使用 time.sleep()。在这种情况下,逻辑是如果按下按钮,那么验证像素的任务将每 T 秒执行一次,直到用户按下 q 键。

from functools import cached_property

from PyQt5.QtCore import pyqtSignal, QObject, QTimer
from PyQt5.QtWidgets import QApplication, QMainWindow, QLabel, QPushButton

import pyautogui
import keyboard

import win32api
import win32con


class KeyBoardHelper(QObject):
    pressed = pyqtSignal()

    def __init__(self, hotkey="", parent=None):
        super().__init__(parent)
        self._hotkey = hotkey

    @property
    def hotkey(self):
        return self._hotkey

    @hotkey.setter
    def hotkey(self, hotkey):
        self.stop()
        self._hotkey = hotkey

    def start(self):
        keyboard.add_hotkey(self.hotkey, self._callback)

    def stop(self):
        try:
            keyboard.remove_hotkey(self._callback)
        except KeyError:
            pass

    def _callback(self):
        self.pressed.emit()


class MouseHelper:
    def click(self, x, y):
        win32api.SetCursorPos((x, y))
        self._press()

    def _press(self):
        win32api.mouse_event(win32con.MOUSEEVENTF_LEFTDOWN, 0, 0)
        QTimer.singleShot(10, self._release)

    def _release(self):
        win32api.mouse_event(win32con.MOUSEEVENTF_LEFTUP, 0, 0)


class MainWindow(QMainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()
        self.setGeometry(400, 400, 600, 480)
        self.setWindowTitle("HBCheat")
        self.initUI()

        self.keyboard_helper.pressed.connect(self.handle_keyboard_pressed)
        self.keyboard_helper.hotkey = "q"

        self.timer.timeout.connect(self.verify_pixel)

    @cached_property
    def keyboard_helper(self):
        return KeyBoardHelper()

    @cached_property
    def mouse_helper(self):
        return MouseHelper()

    @cached_property
    def timer(self):
        return QTimer(interval=10)

    def initUI(self):
        self.label = QLabel(self)
        self.label.setText("Reaction Cheat")
        self.label.move(10, 0)

        self.b1 = QPushButton(self)
        self.b1.setText("Toggle: off")
        self.b1.move(10, 35)
        self.b1.clicked.connect(self.reaction_cheat)

    def click(self, x, y):
        print("X")
        """"
        """

    def reaction_cheat(self):
        self.b1.setText("Toggle: on")
        self.keyboard_helper.start()
        self.timer.start()

    def handle_keyboard_pressed(self):
        self.keyboard_helper.stop()
        self.timer.start()
        self.b1.setText("Toggle: off")

    def verify_pixel(self):
        try:
            if pyautogui.pixel(1298, 415)[1] == 219:
                self.mouse_helper.click(1298, 415)
        except:
            pass


def main():
    import sys

    app = QApplication(sys.argv)
    w = MainWindow()
    w.show()
    sys.exit(app.exec_())


if __name__ == "__main__":
    main()

【讨论】:

    猜你喜欢
    • 2020-04-18
    • 2016-05-09
    • 1970-01-01
    • 1970-01-01
    • 2010-11-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-22
    相关资源
    最近更新 更多