[英]Correct handling of KeyEvent in Pyqt5, problem with catching KeyPressEvent
I have KeyEvent(self, event)
function and transfer event.key()
to function in module MoveKeyboard
but only catch KeyReleaseEvent
.我有
KeyEvent(self, event)
函数并将event.key()
传输到模块MoveKeyboard
但只捕获KeyReleaseEvent
。 I need to handle the release and continuous holding of the button and execute appropriate action .我需要处理按钮的释放和持续按住并执行适当的操作。 I tested
KeyEvent(self, event)
and in console output is only: 1: Release .我测试了
KeyEvent(self, event)
并且在控制台输出中只有: 1: Release 。
Joy, rviz, ..., move_keyboard have PyQt5.QtWidgets.QWidget class. Joy, rviz, ..., move_keyboard 有 PyQt5.QtWidgets.QWidget 类。
Main window code:主窗口代码:
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)
Class MoveKeyoard:类移动键盘:
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_)
If a widget consumes the QKeyEvent
event ( event.accept()
) then that event will not be propagated, in this case QDoubleSpinBox
consumes the events they use as a Qt.ControlModifier
modifier so that other widgets will not receive the press, only the release.如果小部件消耗
QKeyEvent
事件( event.accept()
),则该事件将不会传播,在这种情况下, QDoubleSpinBox
消耗它们用作Qt.ControlModifier
修饰符的事件,以便其他小部件不会收到新闻,只有发布.
So the solution in this case is to prevent the QDoubleSpinBox from consuming the combination Ctrl + W , Ctrl + S , Ctrl + A and Ctrl + D .所以在这种情况下的解决方案是防止 QDoubleSpinBox 使用组合Ctrl + W 、 Ctrl + S 、 Ctrl + A和Ctrl + D 。
On the other hand I do not need the window to handle these events, I think it is better for the widget itself to handle them.另一方面,我不需要窗口来处理这些事件,我认为小部件本身处理它们会更好。
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_())
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.