PDA

View Full Version : [solved] QMenu popup on QTableView does not close after selecting QAction



boo9
12th June 2016, 16:03
Right Click created menu on top of QTableView does not go away after clicking on action item.

After the right click on QTableView the menu pops up.
- 1st click on menu item (triggers signal/slot), but dont close the menu, 2nd click anywhere does close the menu.
- 1st click anywhere (outside of menu) does not close the menu, 2nd click anywhere closes the menu.

How do I force to close the menu after item triggered event ?


void myRLCstuff::on_tableView_customContextMenuRequeste d(const QPoint &pos)
{
QMenu * menu = new QMenu(this);
// connect(menu, SIGNAL(triggered(QAction*)), this, SLOT(testMenu_actionTriggered(QAction*)));
QAction * action = new QAction("&Add Record", menu);
menu->addAction(action);
// connect(action, SIGNAL(triggered()), this, SLOT(on_action_AddRecord_triggered()));
menu->popup(ui->tableView->viewport()->mapToGlobal(pos));
}

I have been on this for hours,
- I tried connect(triggered, testMenu_actionTriggered) and issuing menu->hide/close in testMenu_actionTriggered to no avail
- I tried one shot timer delay 100ms, => (menu, close/hide) to no avail.
- I tried 'menus' example and it works there as expected, but in my app using QTableView this dont work.
- If I add "QMessageBox popup before "menu->popup" line, I need two clicks on button "OK" to dismiss the button :(

qt version 5.5.1 (qt creator 3.6)

EDIT: I realized that the custom context event was firing up two times.
In UI editor, I had contextMenuPolicy=DefaultContextMenu, and in the code I had


view->setContextMenuPolicy(Qt::CustomContextMenu);
connect(view, SIGNAL(customContextMenuRequested(QPoint)), this,
SLOT(on_tableView_customContextMenuRequested(QPoin t)));

That was causing on_tableView_customContextMenuRequested to fire twice

I fixed this by deleting above code and setting UI editor contextMenuPolicy=CustomContextMenu
I dont understand though how qt runtime connects contextMenuPolicy=CustomContextMenu setting to on_tableView_customContextMenuRequested() member ?

anda_skoa
12th June 2016, 17:06
When you set Qt::CustomContextMenu it makes the widget emit the contextMenuRequested() signal.

You named a method "on_" + widget object name + "_" + signal name, which triggers the auto-connect feature in code generated from designer.
Your code then additionally made a manual connect, connecting the signal to the slot twice, getting it executed two times for each signal emit.

Recommendations:
1) do not use the name based auto-connect, always use manual connects

2) for the use case of just having your own actions in the context menu, just add the actions using QWidget::addAction() and set the context menu policy to [noparse]Qt::ActionsMenuPolicy[/norparse].

Cheers,
_

boo9
12th June 2016, 20:17
> 1) do not use the name based auto-connect, always use manual connects
Not even for standard file/edit/help menus ?
I am not sure I understand 'auto-connect', can you please nudge me into right URL about this topic ?

> Qt::ActionsMenuPolicy
nothing in google on this enum :(

anda_skoa
12th June 2016, 20:32
> 1) do not use the name based auto-connect, always use manual connects
Not even for standard file/edit/help menus ?

No, always connect explicitly, it is robust against object name changes.



I am not sure I understand 'auto-connect', can you please nudge me into right URL about this topic ?

The code generated from the .ui file will look for slot names that match the "on_" + object name + "_" + signal name pattern and then look if one of the objects it generated code for has such a name and signal and if yes, connect that signal to the slot.

In my opinion that should never have been added, but I guess, back then they wanted to appease the Delphi/VB crowds who can't be bothered to write a single line of code and need to have all done by the IDE.

And yes it works as intended, but it has way too many drawbacks, being totally hidden being one of them.



> Qt::ActionsMenuPolicy
nothing in google on this enum :(

Right, sorry, typed that out of memory. It is Qt::ActionsContextMenu, see http://doc.qt.io/qt-5/qt.html#ContextMenuPolicy-enum

Cheers,
_

boo9
12th June 2016, 20:43
but I guess, back then they wanted to appease the Delphi/VB crowds who can't be bothered to write a single line of code and need to have all done by the IDE.
that's a good one :)
I do second the args for the explicit approach,
Just for the heck of it, how would one setup auto-connect to popup context menu from header part of QTableView ?

anda_skoa
13th June 2016, 09:11
Just for the heck of it, how would one setup auto-connect to popup context menu from header part of QTableView ?

The header view of the table view isn't an explicitly generated object, it is created by the table view.
Only objects for which code is generated are matched against the slot names.
I.e. all objects that are members of the "ui" class.

Another draw back :-)

Cheers,
_

boo9
13th June 2016, 09:13
What is a good scheme to name my slots ?

anda_skoa
13th June 2016, 10:32
If you want to match the signal name, the "on" followed by the signal name is still a good option.

You could even have the "sender" name in there, as long as you don't use underscores to separate the parts.
The sender name could be anything, e.g the type of widget, the conceptual role it has, etc.
E.g.


onContextMenuRequested()
onTableContextMenuRequested()
onRecordViewContextMenuRequested()


For slots that are also called as normal C++ methods, it often makes more sense to use conventional method naming criteria, e.g.


showSomething()

even if it is also connected to a button or action as one of its triggers.

Cheers,
_