Limit QKeySequence/QKeySequenceEdit to only one shortcut

2k Views Asked by At

Is it possible to limit QKeySequence to show only one shortcut in QKeySequenceEdit? Currently now it supports up to 4 shortcuts. My application supports key sequences of only one shortcut, e.g. Ctrl+A or Ctrl+C and not e.g. Ctrl+A, D or Ctrl+C, X, Z.

Is it possible to limit QKeySequence or QKeySequenceEdit to just one key sequence?

4

There are 4 best solutions below

1
On BEST ANSWER

Solved it, not the best solution but quick...If you want something more customize, I think you have to build it yourself...

customkeysequenceedit.h:

#ifndef CUSTOMKEYSEQUENCEEDIT_H
#define CUSTOMKEYSEQUENCEEDIT_H

#include <QKeySequenceEdit>

class QKeyEvent;

class CustomKeySequenceEdit : public QKeySequenceEdit
{
    Q_OBJECT

public:
    explicit CustomKeySequenceEdit(QWidget *parent = 0);
    ~CustomKeySequenceEdit();

protected:
    void keyPressEvent(QKeyEvent *pEvent);
};

#endif // CUSTOMKEYSEQUENCEEDIT_H

customkeysequenceedit.cpp:

#include "customkeysequenceedit.h"

#include <QKeyEvent>

CustomKeySequenceEdit::CustomKeySequenceEdit(QWidget *parent) : QKeySequenceEdit(parent) { }

CustomKeySequenceEdit::~CustomKeySequenceEdit() { }

void CustomKeySequenceEdit::keyPressEvent(QKeyEvent *pEvent)
{
    QKeySequenceEdit::keyPressEvent(pEvent);

    QKeySequence seq(QKeySequence::fromString(keySequence().toString().split(", ").first()));
    setKeySequence(seq);

}
0
On

You can use the [] operator of QKeySequence: http://doc.qt.io/qt-5/qkeysequence.html#operator-5b-5d

So in your interface constructor, write this:

connect(ui->editShortcut, &QKeySequenceEdit::editingFinished, 
        this, &dialog::truncateShortcut);

And add this private method to your dialog class:

void dialog::truncateShortcut()
{
    int value = ui->editShortcut->keySequence()[0];
    QKeySequence shortcut(value);
    ui->editShortcut->setKeySequence(shortcut);
}

Doing that, you fully respect the API and don't depend on the , character, which is quite risky.

0
On

Most answers is to truncate shortcut after the input done. Anyway, it will show more than one shorcut in the process of inputing, which is kind of annoying.

I found a solutioin that will not even show more than one shorcut.

After one shortcut is inputed, finish the input via clear focus and setKeySequence via override QKeySequenceEdit class keyPressEvent function.

What's more, this method is very easy and graceful!

First create a class myKeySequenceEdit inheriated from QKeySequenceEdit, and below is the codes:

mykeysequenceedit.h:

#ifndef MYKEYSEQUENCEEDIT_H
#define MYKEYSEQUENCEEDIT_H

#include <QKeySequenceEdit>
#include <QWidget>

class myKeySequenceEdit : public QKeySequenceEdit
{
    Q_OBJECT
public:
    myKeySequenceEdit(QWidget *parent = nullptr);

    void keyPressEvent(QKeyEvent *) override;
};

#endif // MYKEYSEQUENCEEDIT_H

mykeysequenceedit.cpp:

#include "mykeysequenceedit.h"

myKeySequenceEdit::myKeySequenceEdit(QWidget *parent) : QKeySequenceEdit(parent) {}

void myKeySequenceEdit::keyPressEvent(QKeyEvent *event)
{
    QKeySequenceEdit::keyPressEvent(event);
    if (this->keySequence().count() > 0) {
        QKeySequenceEdit::setKeySequence(this->keySequence());
        
        emit editingFinished(); // Optinal, depend on if you need the editingFinished signal to be triggered
    }
}
0
On

My take on this: why would we like to wait in edit mode, if just singular shortcut is wanted. Thus interrupting edit immediately on success:

inline bool QKeySequence_valid( const QKeySequence& accelerator ){
    return !accelerator.isEmpty() && accelerator[0] != Qt::Key_unknown;
}

class Single_QKeySequenceEdit : public QKeySequenceEdit
{
protected:
    void keyPressEvent( QKeyEvent *e ) override {
        QKeySequenceEdit::keyPressEvent( e );
        if( QKeySequence_valid( keySequence() ) )
            editingFinished();
    }
};

Real implementation, because i was struggling to find one of this sort:

class Single_QKeySequenceEdit : public QKeySequenceEdit
{
protected:
    void keyPressEvent( QKeyEvent *e ) override {
        QKeySequenceEdit::keyPressEvent( e );
        if( QKeySequence_valid( keySequence() ) )
            clearFocus(); // trigger editingFinished(); via losing focus 
                          // because this can still receive focus loss b4 getting deleted (practically because modal msgbox)
                          // and two editingFinished(); b no good
    }
    void focusOutEvent( QFocusEvent *event ) override {
        editingFinished();
    }
    bool event( QEvent *event ) override { // comsume ALL key presses including Tab
        if( event->type() == QEvent::KeyPress ){
            keyPressEvent( static_cast<QKeyEvent*>( event ) );
            return true;
        }
        return QKeySequenceEdit::event( event );
    }
};

void accelerator_edit( QTreeWidgetItem *item ){
        auto edit = new Single_QKeySequenceEdit;
        QObject::connect( edit, &QKeySequenceEdit::editingFinished, [item, edit](){
            const QKeySequence accelerator = edit->keySequence();
            item->treeWidget()->setItemWidget( item, 1, nullptr );
            if( QKeySequence_valid( accelerator ) )
                accelerator_alter( item, accelerator );
        } );
        item->treeWidget()->setItemWidget( item, 1, edit );
        edit->setFocus(); // track sanity gently via edit being focused property
}