如何停止在键盘 + PyQt5 的单独线程模块中等待按键?

How to stop waiting for a keypress in a separate thread module in keyboard + PyQt5?

我正在编写一个 PyQt5 GUI 程序来控制无人机,我需要跟踪击键。我在用 QThread 创建的单独线程中跟踪它们。当我第一次按下按钮时,击键跟踪应该开始,但我第二次按下按钮时,流程应该停止,击键跟踪也应该停止。这是我的代码:

class Keybord_Recognition(QtCore.QObject):

    def __init__(self):
        super(Keybord_Recognition, self).__init__()

    def key_recog(self, k):
        if k.event_type == 'down':
            if k.name == 'w':
                print('forward')

            elif k.name == 's':
                print('back')

            elif k.name == 'a':
                print('left')

            elif k.name == 'd':
                print('right')

            elif k.name == 'z':
                print('up')

            elif k.name == 'x':
                print('down')

    def run(self):
        keyboard.hook(self.key_recog)
        keyboard.wait('p')

class Ui_MainWindow(object):

    def setupUi(self, MainWindow):
        self.control_btn = QtWidgets.QPushButton(self.centralwidget)
        self.control_btn.setGeometry(QtCore.QRect(480, 60, 160, 150))
        self.control_btn.setObjectName("control_btn")
        self.control_btn.setCheckable(True)
        self.control_btn.clicked.connect(self.kboard_recognition)
        self.control_btn.setStyleSheet("QPushButton{background-color: #aae053;\n"
                                   "border-radius: 60%;\nbackground-image: url('images/pult.png');\n"
                                   "background-repeat: no-repeat;\nbackground-position: center;}\n"
                                   "QPushButton:hover{background-color: #81eb3b;}")

    def kboard_recognition(self):
        if self.control_btn.isChecked():
            self.control_btn.setStyleSheet("QPushButton{background-color: red;\n"
                                       "border-radius: 60%;\nbackground-image: url('images/pause.png');\n"
                                       "background-repeat: no-repeat;\nbackground-position: center;}\n")
            self.thread_kboard = QtCore.QThread()
            self.k_recog = Keybord_Recognition()

            self.k_recog.moveToThread(self.thread_kboard)
            self.thread_kboard.started.connect(self.k_recog.run)
            self.thread_kboard.start()

        else:
            self.control_btn.setStyleSheet("QPushButton{background-color: #aae053;\n"
                                       "border-radius: 60%;\nbackground-image: url('images/pult.png');\n"
                                       "background-repeat: no-repeat;\nbackground-position: center;}\n"
                                       "QPushButton:hover{background-color: #81eb3b;}")

            keyboard.send('q')
            self.thread_kboard.terminate()

但是当我第二次按下按钮时,键盘并没有停止跟踪。如何解决?

与Qt一起使用键盘不需要使用线程,另一方面你必须删除回调以便不再解析事件。

import keyboard

from PyQt5 import QtCore, QtWidgets


class QKeyBoard:
    def _hook_callback(self, k):
        if k.event_type == "down":
            if k.name == "w":
                print("forward")

            elif k.name == "s":
                print("back")

            elif k.name == "a":
                print("left")

            elif k.name == "d":
                print("right")

            elif k.name == "z":
                print("up")

            elif k.name == "x":
                print("down")

    def start(self):
        keyboard.hook(self._hook_callback)

    def stop(self):
        keyboard.unhook(self._hook_callback)


class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        self.centralwidget = QtWidgets.QWidget()
        self.setCentralWidget(self.centralwidget)
        self.control_btn = QtWidgets.QPushButton(self.centralwidget)
        self.control_btn.setGeometry(QtCore.QRect(480, 60, 160, 150))
        self.control_btn.setObjectName("control_btn")
        self.control_btn.setCheckable(True)
        self.control_btn.setStyleSheet(
            "QPushButton{\n"
            "background-color: #aae053;\n"
            "border-radius: 60%;\n"
            "background-image: url('images/pult.png');\n"
            "background-repeat: no-repeat;\n"
            "background-position: center;}\n"
            "QPushButton:hover{\n"
            "background-color: #81eb3b;\n"
            "}"
            "QPushButton:checked{\n"
            "background-color: red;\n"
            "border-radius: 60%;\n"
            "background-image: url('images/pause.png');\n"
            "background-repeat: no-repeat;\n"
            "background-position: center;\n"
            "}"
        )


class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setupUi(self)

        self.qkeyboard = QKeyBoard()
        self.control_btn.toggled.connect(self.handle_toggled)

    def handle_toggled(self, state):
        if state:
            self.qkeyboard.start()
        else:
            self.qkeyboard.stop()


def main():
    import sys

    app = QtWidgets.QApplication(sys.argv)

    w = MainWindow()
    w.resize(640, 480)
    w.show()

    sys.exit(app.exec_())


if __name__ == "__main__":
    main()