1

I have a GameScreen widget that uses keyPressEvent and keyReleaseEvent to take L/R arrow key input. The events are connected to a signal that tells a QGraphicsItem inside GameScreen called Paddle to advance, and Paddle has a paint event that updates the screen. From my qDebug statements, it seems that keyReleaseEvent always triggers before keyPressEvent, forcing the user to give an extraneous input to trigger keyReleaseEvent before keyPressEvent can process anything.

What has worked: My original implementation did not use QGraphicsScene or QGraphicsView, and used QPainter paint() triggered by a timer in GameScreen. There were no issues with keyPressEvent or keyReleaseEvent.

After studying the Colliding Mice example, I changed GameScreen to use QGraphicsScene instead of QPainter; keyPressEvent and keyReleaseEvent code remain unchanged. That's where problems started.

Workaround: Originally keyEventPress and keyReleaseEvent didn't trigger at all after the switch to QGraphicsScene. After reading this SO post, I managed to get the input working again by putting setFocus() inside keyReleaseEvent.

Issue #1: Only keyReleaseEvent is processed if I don't have setFocus() in the code at all or inside keyPressEvent. So there's something blocking keyPressEvent from being able to trigger unless keyReleaseEvent activates first.

Issue #2: As mentioned in the first paragraph, the keyReleaseEvent setFocus() workaround requires pressing and releasing L/R key before the program starts triggering keyPressEvent. At this point, I might have to do a dirty hack and use a stimulated key press so the user doesn't have to.

Here's the relevant code I have. I am going to see if this solution works but I'd rather not rely on hacks to get this working. Sorry for the long post, and if any brave soul can explain what's causing this weird issue and any way to fix it, I would be extremely appreciative! Thanks in advance.

GameScreen.cpp:

GameScreen::GameScreen(QWidget *parent) : QWidget(parent)
{
  paddle = new Paddle();
  scene = new QGraphicsScene(0, 0, 640, 480, this);
  timer = new QTimer(this);
  timer->start(20);
  connect(timer, SIGNAL(timeout()), scene, SLOT(advance()));
}
void GameScreen::keyReleaseEvent(QKeyEvent *e){
  setFocus();
  if(!e->isAutoRepeat()){
    switch(e->key()){
      case Qt::Key_Left:{
          paddle->setKeepLeft(false);
          qDebug() << "Left released";
          break;
        }
      case Qt::Key_Right:{
          paddle->setKeepRight(false);
          qDebug() << "Right released";
          break;
        }
      default:
        QWidget::keyReleaseEvent(e);
      }
  }
}
void GameScreen::keyPressEvent(QKeyEvent *e){
  if(!e->isAutoRepeat()){
    switch(e->key()){
      case Qt::Key_Left:{
          paddle->setKeepLeft(true);
          qDebug() << "Left";
        break;
      }
      case Qt::Key_Right:{
          paddle->setKeepRight(true);
          qDebug() << "Right";
        break;
      }
      default:
        QWidget::keyPressEvent(e);
      }
  }
}

Paddle.cpp:

Paddle::Paddle()
{
  x = 280, y = 400, speed = 8;
  width = 80, height = 10;
  QColor color("powderblue");
  style = new QBrush(color, Qt::SolidPattern); //not sure how to add QColor inline
  keepLeft = false, keepRight = false;
}
QRectF Paddle::boundingRect() const{
  return QRectF(x, y, width, height);
}
void Paddle::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *){
  painter->setPen(Qt::NoPen);
  painter->setBrush(*style);
  painter->drawRect(getShape());
}
void Paddle::advance(int step){
  if(!step)
    return;
  if(keepLeft == true){
      moveLeft();
      update();
    }
  else if(keepRight == true){
      moveRight();
      update();
    }
  return;
}
void Paddle::moveLeft(){
  if(x > 0){
    x -= speed;
  }
}
void Paddle::moveRight(){
  if(x < (640-width)){
    x += speed;
  }
}
QRectF Paddle::getShape(){
  return QRectF(x, y, width, height);
}
QBrush Paddle::getBrushStyle(){
  return *style;
}
void Paddle::setKeepLeft(bool val){
  keepLeft = val;
}
void Paddle::setKeepRight(bool val){
  keepRight = val;
}
Community
  • 1
  • 1
DPC
  • 13
  • 3
  • 1
    This might be because QGraphicsScene/View do press/release event handling a little differently. Look at http://doc.qt.io/qt-5/qgraphicsscene.html#mousePressEvent and http://doc.qt.io/qt-5/qgraphicsscene.html#mouseReleaseEvent (note the special event subclass QGraphicsSceneMouseEvent) and try to use those. – Frank Osterfeld Feb 01 '16 at 05:52
  • Hi Frank, thanks for responding. I checked what you linked, and from what I understand, this is the process: 1. Create a derived class (call it Scene) from QGraphicsScene, pass the parameters to the QGraphicsScene base constructor. 2. In Scene, override keyPressEvent and keyReleaseEvent. from QGraphicsScene default implementation. This is where the process feels muddy to me. Should I connect Scene and Paddle and send Scene's keyboard events to Paddle? Or is there a way to directly access Paddle from Scene? I only see itemAt and items functions, which isn't direct access. 3. Use Paddle's paint. – DPC Feb 03 '16 at 02:04

0 Answers0