I'm trying to design an image viewer application where I use a QGraphicsView to display my images. I want to enable the user to use the arrow keys to open the next/previous image, but my QGraphicsView is always consuming my keyPressEvent. I would like these events to be handled by my QMainWindow class instead. I realize this is a common issue, and apparently I can solve it by installing an event filter and/or ensuring that my QMainWindow can have focus. I have done both, but so far the only thing I have done is to not let the QGraphicsView get the event, but it still does not propagate to the QMainWindow. So far I've implemented the eventFilter
method in my QMainWindow
class and installed it on my QGraphicsView
object.
QMainWindow class
IVMainWindow::IVMainWindow(QWidget *parent)
: QMainWindow(parent)
{
setWindowTitle("ImageViewer++");
setFocusPolicy(Qt::StrongFocus); // Enabled the QMainWindow to get focus
m_image_widget = new IVImageWidget();
m_image_widget->installEventFilter(this); // Install event filter on QGraphicsView
setCentralWidget(m_image_widget);
resize(QGuiApplication::primaryScreen()->availableSize() * 3 / 5);
// For DEBUG purpose
loadImage("res/image.png");
createMenuBar();
createToolBar();
}
/**
* Filters out arrow key presses.
*/
bool IVMainWindow::eventFilter(QObject *obj, QEvent *event) {
if (event->type() == QEvent::KeyPress) {
auto *keyEvent = static_cast<QKeyEvent *>(event);
int key = keyEvent->key();
// Return true to reject the key-presses
return (key == Qt::Key_Left || key == Qt::Key_Right || key == Qt::Key_Up || key == Qt::Key_Down);
} else {
// standard event processing
return QMainWindow::eventFilter(obj, event);
}
}
//Never gets to this point, unless I explicitly give it focus by clicking on some other widget than the QGraphicsView...
void IVMainWindow::keyPressEvent(QKeyEvent *event) {
if (event->key() == Qt::RightArrow) {
m_logger.Debug("Right arrow pressed.");
} else if (event->key() == Qt::LeftArrow) {
m_logger.Debug("Left arrow pressed.");
}
}
You need to process the event in the event filter, it is ok to call QMainWindow::eventFilter for sanity but it do not process the event as an incoming event, so the event handlers will not be called.
bool IVMainWindow::eventFilter(QObject *obj, QEvent *event) {
if (event->type() == QEvent::KeyPress) {
auto *keyEvent = static_cast<QKeyEvent *>(event);
int key = keyEvent->key();
// Return true to reject the key-presses
if (key == Qt::Key_Left || key == Qt::Key_Right || key == Qt::Key_Up || key == Qt::Key_Down)
{
//process event here somehow, or instruct your class to do it later
return true; //filter the event
}
} else {
// standard event processing
return QMainWindow::eventFilter(obj, event);
}
}
//This will only be called for the 'real' events, the ones that eventually are received by the main window
void IVMainWindow::keyPressEvent(QKeyEvent *event) {
if (event->key() == Qt::RightArrow) {
m_logger.Debug("Right arrow pressed.");
} else if (event->key() == Qt::LeftArrow) {
m_logger.Debug("Left arrow pressed.");
}
}