Почему QAbstractButton испускает все сигналы при использовании навигации по клавиатуре?

У меня есть несколько пользовательских кнопок, полученных из QAbstractButton с autoExclusive а также checkable свойство ИСТИНА применяется к одному и тому же родителю.(таким образом, только один элемент может быть проверен одновременно).

Родитель QDialog и я хочу, чтобы всякий раз, когда отображалось диалоговое окно, например, элемент 1, получал фокус клавиатуры, чтобы пользователь мог легко перемещаться между элементами с клавиатуры, НО запускать какую-либо функцию только в том случае, если пользователь выбирает элемент с отпусканием мыши.

Когда я ловлю сигналы на клавиатуре навигации (для пункта 2 в этом случае) все QAbstractButton сигналы:

clicked

pressed

released

toggled

будет срабатывать.

Почему это случилось?

Что я могу сделать?

Item а также Dialog реализация:

Item::Item(QWidget *parent) : QAbstractButton(parent) {
    setAutoExclusive(true);
    setCheckable(true);
}

void Item::paintEvent(QPaintEvent *) {
    QPainter p(this);
    p.setPen(Qt::NoPen);
    p.setRenderHint(QPainter::Antialiasing);
    p.setBrush(/*brush*/);
    p.drawRoundedRect(rect(), /* raduis*/, /* radius */);
    p.setRenderHint(QPainter::Antialiasing, false);

    if (isChecked()) p.drawPixmap(rect(), /*pixmap*/);
}

QSize Item::sizeHint() const {
    return QSize(/*size*/, /*size*/);
}

Dialog::Dialog(QWidget *parent) : QDialog(parent) {
    _mainLayout.setContentsMargins(24, 24, 24, 24);
    _mainLayout.setSpacing(12);

    _mainLayout.addWidget(&_item1, 0, 0);
    _mainLayout.addWidget(&_item2, 0, 1);
    _mainLayout.addWidget(&_item3, 0, 2);

    QObject::connect(&_item2, SIGNAL(clicked()), this, SLOT(onItemClicked()));
    QObject::connect(&_item2, SIGNAL(released()), this, SLOT(onItemReleased()));
    QObject::connect(&_item2, SIGNAL(pressed()), this, SLOT(onItemPPress()));
    QObject::connect(&_item2, SIGNAL(toggled(bool)), this, SLOT(onToggle(bool)));
}

void Dialog::showEvent(QShowEvent *e) {
    _item1.setFocus(Qt::TabFocusReason);
    QDialog::showEvent(e);
}

void Dialog::onItemClicked() {
        qDebug() << "CLICKED";
}
void Dialog::onItemReleased() {
        qDebug() << "RELEASED";
}
void Dialog::onItemPPress() {
        qDebug() << "PRESS";
}
void Dialog::onToggle(bool f) {
        qDebug() << "Toggle";
}

1 ответ

Почему [происходит] эта [отправка сигналов] происходит?

Потому что, как правило, приложение не будет заботиться о том, как была активирована кнопка, только о том, что она была активирована. Если бы Qt не излучал эти сигналы в ответ на события нажатия клавиш, люди бы навсегда жаловались, что их кнопки не излучают ожидаемые сигналы, когда кто-то манипулирует ими через клавиатуру, и тогда каждому разработчику придется вручную добавить свою собственную поддержку клавиатуры логика каждой кнопки, чтобы получить ожидаемое поведение.

Что я могу сделать?

Первое, что нужно сделать, это подумать, действительно ли вы хотите прервать поддержку клавиатуры в своем приложении. Большинство людей ожидают, что смогут активировать кнопки с помощью клавиатуры, а люди, которые не могут использовать мышь (например, потому что они слепые и используют программное обеспечение для навигации по экрану, или потому что их мышь в данный момент не подключена) не смогут закрыть диалоговое окно, если вы отключите поддержку клавиатуры.

Предполагая, что вы учли это и все равно хотите идти вперед, я полагаю, что вы можете фиксировать нажатия клавиш, переопределяя keyPressEvent(QKeyEvent *) в подклассах кнопок. Ваша реализация подкласса может проверить, представляет ли переданное ему QKeyEvent одно из ошибочных нажатий клавиш, и если это так, она может просто вызвать accept() для объекта QKeyEvent (и ничего не делать) вместо передачи keyPressEvent() вызвать суперкласс.

В качестве альтернативы, вы можете просто вызвать setFocusPolicy(Qt::NoFocus) для ваших виджетов кнопок, что помешает им когда-либо получить фокус, что, в свою очередь, помешает им когда-либо получать нажатия клавиш.

Другие вопросы по тегам