Reputation: 55
I have KeyEvent(self, event)
function and transfer event.key()
to function in module MoveKeyboard
but only catch 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.
Joy, rviz, ..., move_keyboard have PyQt5.QtWidgets.QWidget class.
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_)
Upvotes: 1
Views: 867
Reputation: 243897
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.
So the solution in this case is to prevent the QDoubleSpinBox from consuming the combination Ctrl+W, Ctrl+S, Ctrl+A and 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_())
Upvotes: 2