1
votes

I have been reading though a couple of examples and post but I just cannot figure out how to add a shortcut to my custom context menu. My GUI has several elements. One of them is a treeView. For the elements in my treeView I would like to have a custom context menu.

My first approach was according to this tutorial here. The context menu itself worked but the shortcuts cannot work if you create the actin within the show function. So my second approach was according to this tutorial. But still my shortcuts do not work and if I use the context menu all actions are called twice...

Since I did not find a tutorial or code example, which matches my case, I hope that someone here can explain to me how this is correctly done in theory. Adding a shortcut to an action for a custom context menu.

  1. Where do I have to declare my action?
  2. What needs to be the parent of the action?
  3. On which widget do I need to call addAction?

Thanks for any hints.

2
May be, the actions (of context menu) with shortcuts have to be added to the tree view also. (Actions might be added to multiple instances.) Otherwise, I cannot image how an action shall be triggerable as long as the context menu has not yet been opened (or even created).Scheff's Cat
@Scheff Thanks for the hint, you were absolutely right! I needed to add the action also to the treeView. This part was missing in all of the examples I looked at.Sikarjan

2 Answers

1
votes

Another way is to add your action also to the parent widget (or main window widget). As mentioned in this reply, adding the same action to multiple widgets is fine and it's the way QActions are supposed to be used.

Example with custom HtmlBrowser class deriving from QTextBrowser:

Ctrl+U shortcut works for this code:

HtmlBrowser::HtmlBrowser(QWidget * parent) : QTextBrowser(parent)
{
    viewSourceAct = new QAction(tr("View/hide HTML so&urce"), this);
    viewSourceAct->setShortcut(tr("Ctrl+U"));
    viewSourceAct->setCheckable(true);
    parent->addAction(viewSourceAct);
    connect(viewSourceAct, &QAction::triggered, this, &HtmlBrowser::viewSourceToggle);
}

and Ctrl+U shortcut does not work with this code (same as above, but without parent->AddAction(...)):

HtmlBrowser::HtmlBrowser(QWidget * parent) : QTextBrowser(parent)
{
    viewSourceAct = new QAction(tr("View/hide HTML so&urce"), this);
    viewSourceAct->setShortcut(tr("Ctrl+U"));
    viewSourceAct->setCheckable(true);
    connect(viewSourceAct, &QAction::triggered, this, &HtmlBrowser::viewSourceToggle);
}

Curiously, parent in this case is another widget (tab widget), not MainWindow. Still, adding parent->addAction() helps. And, unlike your suggested answer, it works even when connecting action to simple methods, without slots. Works for me in Qt 5.15.0. Not quite sure why it works, though. Perhaps, the widget the action is added to must be permanent for shortcuts to work? Looks like a bug in Qt.

0
votes

Thanks to Scheff's hint I got it working. I do not now if this is really the correct way but this works for me.

The action needs to be declared in the constructor of your GUI class (e.g. MainWindow):

actionDel = new QAction(tr("delete"), this);
actionDel->setShortcut(QKeySequence(Qt::Key_Delete));
connect(actionDel, SIGNAL(triggered()), this, SLOT(actionDel_triggered()));

The triggered signal needs to be connected to a slot. Hint: if you create the slot do not use on_ACTIONNAME_triggered, this will interfere with the designer and cause a connection error.

Next add the action to a custom menu

fileContextMenu = new QMenu(this);
fileContextMenu->addAction(actionDel);

And to the widget

ui->treeView->setContextMenuPolicy(Qt::CustomContextMenu);
connect(ui->treeView, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showDirContextMenu(QPoint)));
ui->treeView->addAction(actionDel);

All in the constructor of your GUI class.

To show the context menu use the following code in slot used in the above connect:

QModelIndex index=ui->treeView->indexAt(pos);

// Here you can modify the menu e.g. disabling certain actions

QAction* selectedItem = fileContextMenu->exec(ui->treeView->viewport()->mapToGlobal(pos));

If you do not have a slot for an action, the action can be also handled in the context menu slot, but this does not work with shortcuts!

if(selectedItem == actionOpen){
    on_treeView_doubleClicked(index);
}