Capturing key press in QGraphicsView within main() function?
-
Hello,
I am trying to program a simple game that primarily uses QGraphicsScene and QGraphicsView, both of which are created in the main function of the program (I have no MainWindow). To have the user control the game I simply want them to use the arrow keys. So, I implemented a simple test function to make sure the methodology I researched works:
void keyPressEvent( QKeyEvent* pe ) { switch( pe->key() ) { case Qt::Key_Space: { qDebug() << "Space pressed"; } break; } }
Unfortunately the function is never called. Looking into it some more it seems to me that "keyPressEvent" is a virtual function for widgets that you implement yourself to control its logic. I've seen a good number of examples that discuss this but all are in regards to MainWindow. It seems like I might need to implement a setFocus policy or install an event filter, but I'm not sure how to go about that for my QGraphicsScene since this is not happening within a class (all of the examples I've seen are for capturing key presses within MainWindow.
If any more code is needed please let me know.
Thanks again for this great forum.
EDIT:
Ok so I read a post on stack overflow that suggested making a custom class that inherits QGraphicsView and then override the keyPressEvent function there. But now I've run into trouble doing that.
gameview.h:
#ifndef GAMEVIEW_H #define GAMEVIEW_H #include <QtWidgets> class GameView : public QGraphicsView { public: GameView(); void keyPressEvent(QKeyEvent *e); }; #endif
gameview.cpp:
#include "gameview.h" GameView::GameView() { } void GameView::keyPressEvent(QKeyEvent *pe) { switch( pe->key() ) { case Qt::Key_Space: { qDebug() << "Space pressed"; } break; } }
So now instead of a QGraphicsView I need to create a "GameView", but when I try to instantiate it and hook it to the QGraphicsScene I use:
QGraphicsScene scene; scene.setSceneRect(0, 0, 800, 800); scene.setItemIndexMethod(QGraphicsScene::NoIndex); GameView view(&scene);
I get this error:
main.cpp:51: error: C2664: 'GameView::GameView(const GameView &)': cannot convert argument 1 from 'QGraphicsScene *' to 'const GameView &'
Clearly something is wrong with binding the Gameview to the GraphicsScene but I'm not sure what. I don't know why its expecting a const GameView reference as a normal GraphicsView has either:
QGraphicsView(QWidget * parent = 0)
or
QGraphicsView(QGraphicsScene * scene, QWidget * parent = 0)
as its constructor and just wants a parent, but its probably a flaw in my implementation. I've never had to implement a class that inherits from another in C++/Qt so I'm not totally sure what the right way is.
It would probably be easier for someone to help with this more specific issue but if you have a better idea for my original question feel free to post anyway.
-
Hi! This is an answer to your original question. You can install an event filter on the QApplication object:
keypresseventfilter.h
#ifndef KEYPRESSEVENTFILTER_H #define KEYPRESSEVENTFILTER_H #include <QObject> class KeyPressEventFilter : public QObject { Q_OBJECT public: explicit KeyPressEventFilter(QObject *parent = nullptr); protected: bool eventFilter(QObject *obj, QEvent *event) override; }; #endif // KEYPRESSEVENTFILTER_H
keypresseventfilter.cpp
#include "keypresseventfilter.h" #include <QKeyEvent> #include <QDebug> KeyPressEventFilter::KeyPressEventFilter(QObject *parent) : QObject(parent) { } bool KeyPressEventFilter::eventFilter(QObject *obj, QEvent *event) { if (event->type() != QEvent::KeyPress) return QObject::eventFilter(obj, event); QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event); switch(keyEvent->key()) { case Qt::Key_Space: { qDebug() << "Space"; break; } case Qt::Key_Left: { qDebug() << "Left"; break; } case Qt::Key_Right: { qDebug() << "Right"; break; } default: { qDebug() << "Unhandled"; break; } } return true; }
main.cpp
#include "mainwindow.h" #include <QApplication> #include "keypresseventfilter.h" int main(int argc, char *argv[]) { QApplication a(argc, argv); KeyPressEventFilter *filter = new KeyPressEventFilter(&a); a.installEventFilter(filter); MainWindow w; w.show(); return a.exec(); }
-
This is an answer to your modified question.
customgraphicsview.h
#ifndef CUSTOMGRAPHICSVIEW_H #define CUSTOMGRAPHICSVIEW_H #include <QGraphicsView> #include <QGraphicsScale> class CustomGraphicsView : public QGraphicsView { Q_OBJECT public: explicit CustomGraphicsView(QWidget *parent = nullptr); CustomGraphicsView(QGraphicsScene *scene, QWidget *parent = nullptr); protected: void keyPressEvent(QKeyEvent *event) override; }; #endif // CUSTOMGRAPHICSVIEW_H
customgraphicsview.cpp
#include "customgraphicsview.h" #include <QKeyEvent> CustomGraphicsView::CustomGraphicsView(QWidget *parent) : QGraphicsView(parent) { } CustomGraphicsView::CustomGraphicsView(QGraphicsScene *scene, QWidget *parent) : QGraphicsView(scene, parent) { } void CustomGraphicsView::keyPressEvent(QKeyEvent *event) { switch(event->key()) { case Qt::Key_Space: { qDebug() << "Space"; break; } case Qt::Key_Left: { qDebug() << "Left"; break; } case Qt::Key_Right: { qDebug() << "Right"; break; } default: { qDebug() << "Unhandled"; break; } } }
main.cpp
#include <QApplication> #include "customgraphicsview.h" #include <QGraphicsScene> int main(int argc, char *argv[]) { QApplication a(argc, argv); QGraphicsScene scene; CustomGraphicsView view(&scene); view.show(); return a.exec(); }
-
@Wieland Wow you are just killing it today for me aren't you? Haha. I'll judge which is best for me a give it a roll.
Thanks a bunch (again)!
EDIT:
I ended up going for the event filter route and it works beautifully. Other than the exact syntax the approach also feels pretty intuitive which I like.