0
votes

I am writing an application that will be used on a screen that has some hardware custom buttons (mapped to function key combinations). Each button is used to change the screen displayed, so I thought a stacked widget seems reasonable.

To develop I have created a debug window that that has these buttons as QPushButtons, with the "normal" Mainwindow embedded. When running in release build I was intending to run this as the main window

This all works fine, but key press events are not propagating as I'd expected. Reading the Qt documentation it indicates that the widget with focus would receive the events, so I had assumed the widget shown in the stacked widget would receive the key press but the debug window always receives the key events, regardless of any focus policy I set

Debug Window:

DebugWindow::DebugWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::GVADemo)
{
    ui->setupUi(this);

    MainWindow* main = new MainWindow(this);
    QLayout* layout = new QHBoxLayout;
    layout->addWidget(main);
    layout->setContentsMargins(0,0,0,0);
    ui->frame->setLayout(layout);
}

void GVADemo::keyPressEvent(QKeyEvent *event)
{
    qDebug("GVADemo keyPressEvent %d", event->key());
}

Main Window:

MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    Screen* screen1 = new Screen();

    QStackedWidget* stackedWidget = new QStackedWidget(this);

    stackedWidget->addWidget(screen1);
    stackedWidget->setCurrentWidget(screen1);
    setCentralWidget(stackedWidget);
}

void MainWindow::keyPressEvent(QKeyEvent *event)
{
    qDebug("MainWindow keyPressEvent %d", event->key());
}

Example of screen in stacked widget:

Screen::Screen(QWidget *parent) : QWidget(parent), ui(new Ui::Screen)
{
    ui->setupUi(this);
}

void SAScreen::keyPressEvent(QKeyEvent *event)
{
    qDebug("Screen keyPressEvent %d", event->key());
}
1
I remember that you can install event filters which are triggered before an event is "delivered". (I didn't do it myself - therefore I can only provide this rough hint...)Scheff's Cat
Please, have a look at Qt doc. Event Filters. This looks promising. There is even a small piece of sample code for QEvent::KeyPress...Scheff's Cat
Another option might be shortcuts (beyond Qt world also called "accelerator keys")... SO: Assign shortcut keys to buttons - Qt C++, SO: How to Program custom Keyboard Shortcuts. (Weird, that this wasn't my first idea...)Scheff's Cat

1 Answers

2
votes

The intended effect can be achieved (actually very simple) using short cut keys.

I prepared an MCVE similar to what was described in the question:

// Qt header:
#include <QtWidgets>

int main(int argc, char **argv)
{
  qDebug() << "Qt Version: " << QT_VERSION_STR;
  // main application
#undef qApp // undef macro qApp out of the way
  QApplication qApp(argc, argv);
  // setup GUI
  QWidget qWin;
  QGridLayout qGrid;
  enum { N = 5 };
  QStackedLayout qStack;
  struct Pane {
    QWidget qWidget;
    QVBoxLayout qVBox;
    QLabel qLbl;
    QLineEdit qTxt;
  } panes[N];
  for (int i = 0; i < N; ++i) {
    Pane &pane = panes[i];
    pane.qLbl.setText(QString::fromUtf8("<b>Pane %0</b>").arg(i + 1));
    pane.qLbl.setTextFormat(Qt::RichText);
    pane.qVBox.addWidget(&pane.qLbl, 1, Qt::AlignCenter);
    pane.qVBox.addWidget(&pane.qTxt);
    pane.qWidget.setLayout(&pane.qVBox);
    qStack.addWidget(&pane.qWidget);
  }
  qGrid.addLayout(&qStack, 0, 0, 1, N);
  qGrid.setRowStretch(0, 1);
  QPushButton qBtns[N];
  for (int i = 0; i < N; ++i) {
    QPushButton &qBtn = qBtns[i];
    qBtn.setText(QString::fromUtf8("F%0").arg(i + 1));
    qBtn.setShortcut(Qt::Key_F1 + i);
    qGrid.addWidget(&qBtn, 1, i);
  }
  qWin.setLayout(&qGrid);
  qWin.show();
  // install signal handlers
  for (int i = 0; i < N; ++i) {
    QPushButton &qBtn = qBtns[i];
    QObject::connect(&qBtn, &QPushButton::clicked,
      [&qStack, i](bool) { qStack.setCurrentIndex(i); });
  }
  // run application
  return qApp.exec();
}

I compiled and tested with VS2013 and Qt5.6 in Windows 10 (64 bit):

Snapshot of MCVE

Note:

I tested clicking the buttons as well as using the corresponding function keys. Thereby, I set the focus into the QLineEdit to be sure that it works independently of currently focused widget.


Update:

In the OP, the buttons are hardware buttons. Thus, I modified the first version of the sample to work without QPushButtons. The same effect can be achieved with QActions which are directly added to the main window (using QWidget::addAction()):

// Qt header:
#include <QtWidgets>

int main(int argc, char **argv)
{
  qDebug() << "Qt Version: " << QT_VERSION_STR;
  // main application
#undef qApp // undef macro qApp out of the way
  QApplication qApp(argc, argv);
  // setup GUI
  QWidget qWin;
  QGridLayout qGrid;
  enum { N = 5 };
  QStackedLayout qStack;
  struct Pane {
    QWidget qWidget;
    QVBoxLayout qVBox;
    QLabel qLbl;
    QLineEdit qTxt;
  } panes[N];
  for (int i = 0; i < N; ++i) {
    Pane &pane = panes[i];
    pane.qLbl.setText(QString::fromUtf8("<b>Pane %0</b>").arg(i + 1));
    pane.qLbl.setTextFormat(Qt::RichText);
    pane.qVBox.addWidget(&pane.qLbl, 1, Qt::AlignCenter);
    pane.qVBox.addWidget(&pane.qTxt);
    pane.qWidget.setLayout(&pane.qVBox);
    qStack.addWidget(&pane.qWidget);
  }
  qGrid.addLayout(&qStack, 0, 0, 1, N);
  qGrid.setRowStretch(0, 1);
  QLabel qLbls[N];
  for (int i = 0; i < N; ++i) {
    QLabel &qLbl = qLbls[i];
    qLbl.setText(QString::fromUtf8("F%0").arg(i + 1));
    qGrid.addWidget(&qLbl, 1, i);
  }
  qWin.setLayout(&qGrid);
  QAction *pQCmds[N];
  for (int i = 0; i < N; ++i) {
    QAction *pQCmd = pQCmds[i] = new QAction(&qWin);
    pQCmd->setShortcut(Qt::Key_F1 + i);
    qWin.addAction(pQCmd);
  }
  qWin.show();
  // install signal handlers
  for (int i = 0; i < N; ++i) {
    QObject::connect(pQCmds[i], &QAction::triggered,
      [&qStack, i](bool) { qStack.setCurrentIndex(i); });
  }
  // run application
  return qApp.exec();
}

I compiled and tested again with VS2013 and Qt5.6 in Windows 10 (64 bit):

Snapshot of MCVE (V2)

Note:

The QLineEdits are focused (per default) while the function keys have been used to switch the current index of the QStackLayout.