4
votes

I have some global menu actions which are attached to the main menuBar ("Zoom" in the example below). Additionally, I have actions attached to certain widgets ("Zoom2" in the example below).

I would like to use the same shortcut for both actions. It should work like this:

  • if textEdit2 is focussed, its action should consume the shortcut (i.e. zoom2() should be triggered).
  • otherwise, the menu shortcut should get active, triggering zoomGlobal().

The current example below does not work yet: If textEdit2 is focussed, Qt notifies QAction::eventFilter: Ambiguous shortcut overload: Ctrl++ and does nothing.

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    QAction *act = menuBar()->addAction("Zoom");
    act->setShortcut(QKeySequence("Ctrl++"));
    connect(act, SIGNAL(triggered(bool)), this, SLOT(zoomGlobal()));

    setCentralWidget(new QWidget());
    QVBoxLayout *layout = new QVBoxLayout();
    centralWidget()->setLayout(layout);
    QTextEdit *textEdit1 = new QTextEdit();
    layout->addWidget(textEdit1);

    QTextEdit *textEdit2 = new QTextEdit();
    layout->addWidget(textEdit2);
    act = new QAction("Zoom2");
    act->setShortcut(QKeySequence("Ctrl++"));
    act->setShortcutContext(Qt::WidgetShortcut);
    connect(act, SIGNAL(triggered(bool)), this, SLOT(zoom2()));
    textEdit2->addAction(act);
}

Is there a way for a focussed widget to steal and consume a shortcut, no matter if there is another shorcut with context WindowShortcut or ApplicationShortcut?

Of course, it would be possible to code all the stuff in zoomGlobal(), check which widget is active and delegate to its action. However, that's quite cumbersome if you have many actions and widgets. I would like to be able add/remove/change widgets like textEdit2 without the need to adapt code in zoomGlobal().

1
After more than two hours of search and attemps I have absolutely no idea how it can be done without the global check)). You have to check whether the textEdit2 is active or not active during the global shortcut event. This is not bad, because your program of course will not have many such pairs, and the check is simple )Vladimir Bershov
@VladimirBershov: Thanks for your work. Actually, the above is only a minimal example. The actual program has several widgets like textEdit2 and each with multiple (and different) shortcuts. The global check is nothing I can seriously introduce. If anything, one would have to write a framework around that. All widgets and actions would have to be registered there and the framework would have to delegate. But I hope that there is another way.Tim Hoffmann
Please note that this is a strange example. I don't know anything about your main project, but this peace of code looks bad - non-informative variable names which differ only by numbers, creating UI elements in the code, strange line setCentralWidget(new QWidget()); . Global check is not a problem, it can be just encapsulated in a class, like everything else.Vladimir Bershov
This is really just a minimal example for testing (you can create a project and paste the above code for a working example). You may think of it as a code editor textEdit1 and other related widgets textEdit2. "creating UI elements in the code": IMHO nothing wrong with that. "strange line setCentralWidget(new QWidget());": This is just a container on which I can set the layout. "Global [...] can be just encapsulated in a class": that's what I meant by framework.Tim Hoffmann
I feel your pain, I have exactly this problem too. Having to do the global ckecks is of course possible, but as in your case that would need a quite large framework around it in a real application with lots of widgets/shortcut. Can't understad that there's so little written about this!Peter

1 Answers

1
votes

I had the same problem as you. To solve it, you use a trick inside the QShortcut class.

In your example code, you want 'textEdit2' to steal a global shortcut when it has focus. This code should do it, it works for me:

QTextEdit* textEdit2 = new QTextEdit();
layout->addWidget(textEdit2);
QShortcut* shortcutStealer = new QShortcut(
    QKeySequence("Ctrl++"),  //the key sequence to steal
    textEdit2,               //the shortcut's parent
    SLOT(zoom2()),           //triggered when shortcut activated
    SLOT(zoom2()),           //triggered when shortcut ambiguously activated! 
    Qt::WidgetShortcut);     //context of shortcut

Hope this is clear and helps you. Kind regards!