Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I prevent the enter key from closing my QDialog (Qt 4.8.1)

I have a QDialog with a QDialogButtonBox. The OK and Cancel buttons are active. Occasionally I disable or hide the OK button based on the state of my dialog. It seems, no matter what I do, the Enter key always activates the OK button. I really DON'T want this to happen. I have tried:

  • Setting default and autoDefault properties to false every time I show/hide/enable/disable/whatever the button
  • installing an event filter on the OK button to intercept key events (pressed and released) for return, enter and space
  • Setting the focus policy on the button to NoFocus

And with all combinations of those things above, the Enter key still accepts the dialog. Does anyone have any clue how to block this? It seems like I should be able to block something as simple as this?

like image 646
cppguy Avatar asked Apr 06 '13 00:04

cppguy


4 Answers

The key press event filtering should be done on the dialog itself, because the code handling the forwarding of the Return and Enter keys to the default button is in QDialog::keyPressEvent.

void Dialog::keyPressEvent(QKeyEvent *evt)
{
    if(evt->key() == Qt::Key_Enter || evt->key() == Qt::Key_Return)
        return;
    QDialog::keyPressEvent(evt);
}

Or

theDialog−>installEventFilter(anotherClassObject);

bool AnotherClass::eventFilter(QObject *obj, QEvent *evt)
{
    if(evt->type() == QEvent::KeyPress) {
        QKeyEvent *keyEvent = static_cast<QKeyEvent*>(evt);
        if(keyEvent->key() == Qt::Key_Enter || keyEvent->key() == Qt::Key_Return )
            return true; // mark the event as handled
    }
    return false;
}
like image 124
alexisdm Avatar answered Oct 27 '22 00:10

alexisdm


If you have normal QPushButtons on the dialog then if the buttons have the autoDefault and/or default properties set on them then you get a default button - which is what the enter key triggers. In that case, get rid of autoDefault on the buttons and pressing enter in another widget no longer closes the dialog.

In the case of a QDialogButtonBox you can probably iterate over the buttons to turn this stuff off in the ctor of your dialog. Not tested here but ought to work. If not then you'll need to also see if there is a default button that gets set on the QDialog itself too.

like image 21
Pete Avatar answered Oct 26 '22 22:10

Pete


QDialog has a private slot called accept(). Whenever QDialogButtonBox emits accepted() (by pressing return key or clicking Ok), that private slot is called. So try disconnecting them.

disconnect(ui->buttonBox, SIGNAL(accepted()), this, SLOT(accept()));

This worked for me.

like image 44
Md. Minhazul Haque Avatar answered Oct 26 '22 22:10

Md. Minhazul Haque


The problem is the event filter shouldn't be installed on the OK button.

If your OK button is disabled, then it's not going to receive the enter event. Whichever widget has the focus will. And if they don't accept the enter event, then QDialog is going to accept() itself.

Two ways to solve the problem:

1) Override QDialog::accept(), and call QDialog's accept method in the new accept function only if OK is enabled

void MyDialog::accept() {
    if (okEnabled) {
        QDialog::accept();
    }
}

2) Install an event filter on every widget in the dialog that doesn't accept the enter key (line edits, ...).

The event filter would be like so:

class KeyPressEater : public QObject
{
    Q_OBJECT

protected:
    bool eventFilter(QObject *obj, QEvent *event);
};

bool KeyPressEater::eventFilter(QObject *obj, QEvent *event)
{
    if (event->type() == QEvent::KeyPress) {
        QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
        bool res = QObject::eventFilter(obj, event);

        if (keyEvent->key() == Qt::Key_Return) {
            return true; /* Always accept return */
        } else {
            return res;
        }
    } else {
        // standard event processing
        return QObject::eventFilter(obj, event);
    }
}

And in your code, for each widget in the dialog:

myWidget->installEventFilter(myKeyPressEater);
like image 32
coyotte508 Avatar answered Oct 26 '22 22:10

coyotte508