Reputation: 105
I'm writing a PyQt5 GUI program to control drones and I need to track keystrokes. I keep track of them in a separate thread created with QThread. When I press the button for the first time, the keystroke tracking should start, but the second time I press the button, the flow should stop and the keystroke tracking too. Here is my code:
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()
But when I press the button a second time, the keyboard doesn't stop tracking. How to fix it?
Upvotes: 0
Views: 208
Reputation: 244282
It is not necessary to use threads to use keyboard together with Qt, on the other hand you have to remove the callback so that the events are no longer parsed.
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()
Upvotes: 1