在 Pyqt5 中正确处理 KeyEvent,捕获 KeyPressEvent 时出现问题



我有KeyEvent(self, event)函数并将event.key()转移到模块MoveKeyboard中,但只捕获KeyReleaseEvent。我需要处理按钮的释放和连续按住并执行适当的操作。我测试了KeyEvent(self, event),控制台输出仅为:1:发布

Joy, rviz, ..., move_keyboard 有 PyQt5.QtWidgets.QWidget class.

主窗口代码:

class MainWindow(PyQt5.QtWidgets.QMainWindow):
def __init__(self):
super(MainWindow, self).__init__(None)
self.title = 'Robot teleoperation'
self.left = 10
self.top = 10
self.width = 1920
self.height = 1080
rospy.init_node("gui_node")
#self.joy = Joystick(maxDistance=50,MinimumSize=100,EclipseX=-20,EclipseY=40)
#self.rviz = Rviz()
#self.arm_position = BaseArmPosition()
#self.laser_position = LaserPosition()
#self.move_slider = MoveSlider()
#self.arm_slider = ArmSlider()
self.move_keyboard = MoveKeyboard()
self.initUI()

def initUI(self):
self.central_widget = PyQt5.QtWidgets.QWidget()
self.setCentralWidget(self.central_widget)
grid = PyQt5.QtWidgets.QGridLayout(self.centralWidget())
#grid.addWidget(self.rviz, 0, 0)
#grid.addWidget(self.joy, 0, 1)
#grid.addWidget(self.arm_slider,0,2)
#grid.addWidget(self.arm_position, 1, 0)
#grid.addWidget(self.move_slider, 1,1)
grid.addWidget(self.move_keyboard,0,0)
self.setWindowTitle(self.title)
self.setGeometry(self.left, self.top, self.width, self.height)
self.show() 
def keyPressEvent(self, event):
print("1: Press")
self.move_keyboard.PressEvent(event)
if event.key() == PyQt5.QtCore.Qt.Key_Control:
print("2: Press")
self.move_keyboard.PressEvent(event)
return super(MainWindow, self).keyPressEvent(event)
def keyReleaseEvent(self, event):
print("1: Release")
self.move_keyboard.ReleaseEvent(event)
if event.key() == PyQt5.QtCore.Qt.Key_Control:
print("2: Release")
self.move_keyboard.ReleaseEvent(event)
return super(MainWindow, self).keyReleaseEvent(event)

类移动键:

import PyQt5
import rospy
from geometry_msgs.msg import Twist

class MoveKeyboard(PyQt5.QtWidgets.QWidget):
def __init__(self, *args, **kwargs):
super(MoveKeyboard, self).__init__(*args, **kwargs)            
self.Up = PyQt5.QtWidgets.QLabel("Up(W)")
self.Left = PyQt5.QtWidgets.QLabel("Left(A)")
self.Right = PyQt5.QtWidgets.QLabel("Right(D)")
self.Down = PyQt5.QtWidgets.QLabel("Down(S)")
self.LinearValue = PyQt5.QtWidgets.QDoubleSpinBox(self)
self.AngularValue = PyQt5.QtWidgets.QDoubleSpinBox(self)
self.label_linear = PyQt5.QtWidgets.QLabel("Linear speed")
self.label_angular = PyQt5.QtWidgets.QLabel("Angular speed")
self.initUI()

def initUI(self):
self.LinearValue.setMaximum(1.00)
self.LinearValue.setMinimum(0.00)
self.LinearValue.setSingleStep(0.01)
self.AngularValue.setMaximum(1.00)
self.AngularValue.setMinimum(0.00)
self.AngularValue.setSingleStep(0.01)
layout = PyQt5.QtWidgets.QGridLayout(self)
layout.addWidget(self.label_linear,0,0)
layout.addWidget(self.LinearValue,0,1)
layout.addWidget(self.label_angular,1,0)
layout.addWidget(self.AngularValue,1,1)
layout.addWidget(self.Up,2,1)
layout.addWidget(self.Left,3,0)
layout.addWidget(self.Down,3,1)
layout.addWidget(self.Right,3,2)

self.pub = rospy.Publisher('cmd_vel', Twist, queue_size = 1)
def PressEvent(self, e):
if e.key() == PyQt5.QtCore.Qt.Key_W:
self.Up.setStyleSheet('color: red')
self.do("W")
if e.key() == PyQt5.QtCore.Qt.Key_S:
self.Down.setStyleSheet('color: red')
self.do("S")
if e.key() == PyQt5.QtCore.Qt.Key_A:
self.Left.setStyleSheet('color: red')
self.do("A")
if e.key() == PyQt5.QtCore.Qt.Key_D:
self.Right.setStyleSheet('color: red')
self.do("D")
def ReleaseEvent(self, e):
if e.key() == PyQt5.QtCore.Qt.Key_W:
self.Up.setStyleSheet('color: black')
self.do("---W")
if e.key() == PyQt5.QtCore.Qt.Key_S:
self.Down.setStyleSheet('color: black')
self.do("---S")
if e.key() == PyQt5.QtCore.Qt.Key_A:
self.Left.setStyleSheet('color: black')
self.do("---A")
if e.key() == PyQt5.QtCore.Qt.Key_D:
self.Right.setStyleSheet('color: black')
self.do("---D")
def do(self,str_):
print(str_)

如果一个小部件使用QKeyEvent事件(event.accept()(,那么该事件将不会传播,在这种情况下,QDoubleSpinBox使用它们用作Qt.ControlModifier修饰符的事件,以便其他小部件不会收到媒体,只会收到发布。

因此,在这种情况下,解决方案是防止QDoubleSpinBox使用组合Ctrl +W,Ctrl+S,Ctrl+ACtrl+D

另一方面,我不需要窗口来处理这些事件,我认为小部件本身处理它们更好。

from PyQt5 import QtCore, QtWidgets

class DoubleSpinBox(QtWidgets.QDoubleSpinBox):
def keyPressEvent(self, event):
if event.modifiers() == QtCore.Qt.ControlModifier and event.key() in (
QtCore.Qt.Key_W,
QtCore.Qt.Key_S,
QtCore.Qt.Key_A,
QtCore.Qt.Key_D,
):
event.ignore()
else:
super(DoubleSpinBox, self).keyPressEvent(event)

class MoveKeyboard(QtWidgets.QWidget):
def __init__(self, parent=None):
super(MoveKeyboard, self).__init__(parent)
self.Up = QtWidgets.QLabel("Up(W)")
self.Left = QtWidgets.QLabel("Left(A)")
self.Right = QtWidgets.QLabel("Right(D)")
self.Down = QtWidgets.QLabel("Down(S)")
self.LinearValue = DoubleSpinBox()
self.AngularValue = DoubleSpinBox()
self.label_linear = QtWidgets.QLabel("Linear speed")
self.label_angular = QtWidgets.QLabel("Angular speed")
self.initUI()
def initUI(self):
self.LinearValue.setMaximum(1.00)
self.LinearValue.setMinimum(0.00)
self.LinearValue.setSingleStep(0.01)
self.AngularValue.setMaximum(1.00)
self.AngularValue.setMinimum(0.00)
self.AngularValue.setSingleStep(0.01)
layout = QtWidgets.QGridLayout(self)
layout.addWidget(self.label_linear, 0, 0)
layout.addWidget(self.LinearValue, 0, 1)
layout.addWidget(self.label_angular, 1, 0)
layout.addWidget(self.AngularValue, 1, 1)
layout.addWidget(self.Up, 2, 1)
layout.addWidget(self.Left, 3, 0)
layout.addWidget(self.Down, 3, 1)
layout.addWidget(self.Right, 3, 2)
def get_widget_by_key(self, key):
d = {
QtCore.Qt.Key_W: ("W", self.Up),
QtCore.Qt.Key_S: ("S", self.Down),
QtCore.Qt.Key_A: ("A", self.Left),
QtCore.Qt.Key_D: ("D", self.Right),
}
return d.get(key, ("", None))
def keyPressEvent(self, event):
if event.modifiers() == QtCore.Qt.ControlModifier and not event.isAutoRepeat():
letter, widget = self.get_widget_by_key(event.key())
if widget is not None:
widget.setStyleSheet("color: red")
print(letter)
super(MoveKeyboard, self).keyPressEvent(event)
def keyReleaseEvent(self, event):
if event.modifiers() == QtCore.Qt.ControlModifier and not event.isAutoRepeat():
letter, widget = self.get_widget_by_key(event.key())
if widget is not None:
widget.setStyleSheet("color: black")
print("--{}".format(letter))
super(MoveKeyboard, self).keyReleaseEvent(event)

class MainWindow(QtWidgets.QMainWindow):
def __init__(self):
super(MainWindow, self).__init__(None)
self.title = "Robot teleoperation"
self.move_keyboard = MoveKeyboard()
self.initUI()
def initUI(self):
self.central_widget = QtWidgets.QWidget()
self.setCentralWidget(self.central_widget)
grid = QtWidgets.QGridLayout(self.centralWidget())
grid.addWidget(self.move_keyboard, 0, 0)
self.setWindowTitle(self.title)
self.setGeometry(10, 10, 1920, 1080)

if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())

最新更新