Assigning actions to QMenu items - qt

I have created a Qt project in which I'm using a widget and it does not support any menu in the designer's class, so it should be done programmatically. I succeeded in creating the menu and adding the items but I'm struggling in assigning any action for the menu items...
That's what I've done so far:
QMenuBar* menuBar = new QMenuBar();
QMenu *fileMenu = new QMenu("File");
menuBar->addMenu(fileMenu);
fileMenu->addAction("Save");
fileMenu->addAction("Exit");
QAction* newAct = new QAction(tr("&New"), this);
newAct->setShortcuts(QKeySequence::New);
newAct->setStatusTip(tr("Exit"));
connect(newAct, &QAction::triggered, this, &MainWindow::on_action_triggered);
this->layout()->setMenuBar(menuBar);
But no action is triggered when I press The Exit item

addAction creates QAction and returns pointer to it, you dont need to create it explicitly, but when you do you must add item to menu with addAction, setting parent is not enough fileMenu->addAction(newAct);.

Related

QAction doesn't show QMenu

I'm creating my UI from Qt Designer and it generares this code:
toolBar = new QToolBar(MainWindow);
QIcon icon;
icon.addFile(QStringLiteral(":/main"), QSize(), QIcon::Normal, QIcon::Off);
MainWindow->addToolBar(Qt::TopToolBarArea, toolBar);
actionConvert = new QAction(MainWindow);
actionConvert->setObjectName(QStringLiteral("actionConvert"));
actionConvert->setIcon(icon);
toolBar->addAction(actionConvert);
Now, back in my frame code:
QMenu *menuAdd = new QMenu (this);
menuAdd->addAction (tr("&Files..."));
menuAdd->addAction (tr("&Directory..."));
ui->actionConvert->setMenu (menuAdd);
When I run the application I can see the qaction in the toolbar even the arrow pointing down, which indicates that there is a menu, but when I click it, the menu doesn't appear...any ideas?
There does not seem to be anything wrong with your example code.
It's possible that the reason you aren't seeing the menu is that you need to press and hold the button for a few seconds in order for the menu to appear. A single click will just execute the button's normal action.
See: QToolButton::ToolButtonPopupMode.
You should add menu with menuBar() method as in my case:
void MainWindow::ueInitMenu()
{
this->ueSetCodeRegisterPlacesAction(new QAction(tr("Places"),
this));
this->ueCodeRegisterPlacesAction()->setShortcut(tr("Ctrl+P"));
this->ueCodeRegisterPlacesAction()->setStatusTip(tr("Shows places code register"));
connect(this->ueCodeRegisterPlacesAction(),
SIGNAL(triggered()),
this,
SLOT(ueSlotShowPlacesView()));
this->ueSetCodeRegisterMenu(this->menuBar()->addMenu(tr("Code register")));
this->ueCodeRegisterMenu()->addAction(this->ueCodeRegisterPlacesAction());
} // ueInitMenu
especialy the line:
this->ueSetCodeRegisterMenu(this->menuBar()->addMenu(tr("Code register")));
so in your case:
this->menuBar()->addMenu(tr("System menu");
and then add actions. Also take a look at Menus Example.

Simple ribbon: how to use QActions within QTabBar?

I'm trying to implement simple tabbed interface with Qt5. I use QTabWidget with QToolBars placed inside its tabs and I add QActions to the QToolBars.
That works but causes the following issue: any action remains accessible only while its parent tab is active. If I try to use keyboard shortcut for currently "invisible" action, I will have no success. Since there's no menu etc, the tabs are the only place, where the actions are placed.
Here's how I add the elements to the toolbar:
QTabWidget *ribbon = new QTabWidget(window);
QToolBar *tool_bar_game = new QToolBar(tab_game);
QAction *action_go_to_next_level = new QAction(window);
action_go_to_next_level->setText(QApplication::translate("Window", "&Next", 0));
action_go_to_next_level->setIcon(QIcon::fromTheme("go-last"));
action_go_to_next_level->setShortcut(QApplication::translate("Window", "PgDown", 0));
ribbon->addTab(tool_bar_game, tr("Game"));
tool_bar_game->addAction(action_go_to_next_level);
and a screenshot:
How can I make the action accessible with shortcuts, even when the action's parent tab is not currently opened?
I'm not surprised that this doesn't work, effectively you try to use a shortcut on a hidden widget. It would be very confusing if this worked.
The obvious workaround for this is to add the shortcut instead of to the QAction to a widget that is always active. Personally, I suggest the window.
Without having tested the code, I believe this should work:
QTabWidget *ribbon = new QTabWidget(window);
QToolBar *tool_bar_game = new QToolBar(tab_game);
QAction *action_go_to_next_level = new QAction(window);
action_go_to_next_level->setText(QApplication::translate("Window", "&Next", 0));
action_go_to_next_level->setIcon(QIcon::fromTheme("go-last"));
QShortcut *page_down = new QShortcut(QKeySequence("PgDown"), window);
// trigger the action when the shortcut is activated
QObject::connect(page_down, &QShortcut::activated,
action_go_to_next_level, &QAction::trigger);
ribbon->addTab(tool_bar_game, tr("Game"));
tool_bar_game->addAction(action_go_to_next_level);

QTreeWidget right click menu

I looked around and it seems that the problem is present not only for tree widget but also for other widgets. But in my case, I found a solution, although an incomplete one. I am adding actions to my tree widget, so that when you right click on it, a popup with these actions appears. However, when I add items to my tree widget and I right click on them, the same popup appears.
What I would like to do is that when you right click on the tree widget, a tree widget popup menu appears and when you right click on items, another corresponding popup menu appears. Does anybody knows how to do this?
First,config QTreeWidget to response(emit signal) right mouse click:
treeWidget->setContextMenuPolicy(Qt::CustomContextMenu);
Second,connect the signal with your slot "MainWindow::prepareMenu":
connect(treeWidget,&QTreeWidget::customContextMenuRequested,this,&MainWindow::prepareMenu);
Third,create context menu in the slot:
void MainWindow::prepareMenu( const QPoint & pos )
{
QTreeWidget *tree = treeWid;
QTreeWidgetItem *nd = tree->itemAt( pos );
qDebug()<<pos<<nd->text(0);
QAction *newAct = new QAction(QIcon(":/Resource/warning32.ico"), tr("&New"), this);
newAct->setStatusTip(tr("new sth"));
connect(newAct, SIGNAL(triggered()), this, SLOT(newDev()));
QMenu menu(this);
menu.addAction(newAct);
QPoint pt(pos);
menu.exec( tree->mapToGlobal(pos) );
}
First you should set the context menu policy to CustomContextMenu:
treeView->setContextMenuPolicy(Qt::CustomContextMenu);
Then you can connect to the QWidget::customContextMenuRequested(const QPoint&) signal and show your context menu.
For those who prefer to use designer more, here is another way to do it:
1) Set context menu policy to custom context menu
Either by code:
ui->treeWidget->setContextMenuPolicy(Qt::CustomContextMenu);
or using graphical designer, click on the tree widget and set it using Property Editor:
2) Create Handler function
In designer, right click on the treeWidget and select "Go to Slot..." option. A window similar to this will appear:
Click on the "CustomContextMenuRequested(QPoint)" option. Handler function will be defined, declared, and it will be connected automatically.
void MainWindow::on_treeWidget_customContextMenuRequested(const QPoint &pos)
{
// this function will be called on right click
}
This step can also be done by defining and connecting the slot function yourself.
3) Create the options on the context menu.
Go to action editor tab (Usually docked at the bottom of designer). Add actions you want to have on context menu by clicking new button on top left. You will encounter such an interface :
You can (optionally) have a tooltip or icon for the action, or make it checkable. You can crate a shortcut like Ctrl+C for a copy action.
4) Create the menu and fire it
void MainWindow::on_treeWidget_customContextMenuRequested(const QPoint &pos)
{
QMenu menu(this); // add menu items
menu.addAction(ui->actionDelete);
menu.addEdit(ui->actionDelete);
...
ui->actionDelete->setData(QVariant(pos)); // if you will need the position data save it to the action
menu.exec( ui->treeWidget->mapToGlobal(pos) );
}
5) Create handler functions for each action
Like in step 2, either create slot function and connect it manually, or right-click on on an action, click the "Go to slots..." option and select triggered() slot.
6) Lastly, apply your logic in the slot function
void MainWindow::on_actionEdit_triggered()
{
QTreeWidgetItem *clickedItem = ui->treeWidget->itemAt(ui->actionDelete->data().toPoint());
// your logic
}
Take a look at overloading QAbstractItemModel and providing your own OnContextMenuRequested. Via this function you can have different items create different context menus.
Here's some shortened pseudo-ish code from one of my projects that may be helpful:
void MyModel::OnContextMenuRequested(const QModelIndex& index, const QPoint& globalPos)
{
// find 'node' corresponding to 'index'
vector<pair<string,BaseNode*> > actions = node->GetActions(true);
if(actions.size()==0) return;
// the ptr list helps us delete the actions
boost::ptr_list<QObject> actionPtrList;
QList<QAction*> qtActions;
for(unsigned int i=0;i<actions.size();i++)
{
QAction* act = new QAction(actions[i].first.c_str(),NULL);
act->setData(qVariantFromValue(actions[i].second));
actionPtrList.push_back(act);
qtActions.append(act);
}
// create and show the context menu
QMenu *menu = new QMenu("Item actions",NULL);
actionPtrList.push_back(menu);
QAction* act = menu->exec(qtActions,globalPos);
if(act==NULL) return;
// act on the resulting action 'act'
}

QT: Context menu (QMenu) reference from the QTableWidget

I want to add a submenu in my context menu which is created like this:
self.widget_alignment.setContextMenuPolicy(Qt.ActionsContextMenu)
where widget_alignment is QTableWidget.
I created a new QMenu instance:
exchange_bases_menu = QMenu(self.widget_alignment)
added some actions, and I found a method QAction QMenu.addMenu (self, QMenu menu)
but I don't see any reference to the default context menu for self.widget_alignment.
Additionally, this code:
self.widget_alignment.addMenu(exchange_bases_menu)
gave me: QTableWidget object has no attribute addMenu.
How can I add my submenu to the default context menu?
According to the documentation, when a QWidget is set to have the actions context menu type, the widget will construct a context menu based on the list of actions set for the widget. To modify the list of actions, you can call addAction, insertAction, or removeAction. So I would expect you could do something like this (in C++):
QAction *act_p = new QAction( "Has Submenu", widget_alignment );
QMenu *submenu_p = new QMenu( act_p );
// Add items to the submenu
act_p->setMenu( submenu_p );
widget_alignment->addAction( act_p );
Without trying it myself, I would expect this to add a "Has Submenu" option to the bottom of the context menu that is generated for the widget, with the submenu you created as the submenu shown.
What about using QMenu's popup() in MouseReleaseEvent?
if (pEvent->button() == Qt::RightButton)
{
QMenu menu;
menu.addAction(action1);
menu.addAction(action2);
menu.popup(pEvent->globalPos(),action1);
}

On Qt widgets like DoubleSpinBox or ComboBox, how do i have custom right click menu

I have a few combo-boxes and double spin boxes on my Qt Dialog. Now I need a "ResetToDefault" item on a menu that comes up when you right click on the widget (spin box or combo box).
How do i get it. Is there some way I can have a custom menu that comes up on right click or Is there a way i can add items to the menu that comes on right click.
First, for Qt4, the simplest way is to create an action to reset the data, and add it the the widget using the addAction method (or use the designer). Then, set the contextMenuPolicy attribute to Qt::ActionsContextMenu. The context menu will appear and the action will be triggered.
Code example:
QAction *reset_act = new QAction("Reset to default");
mywidget->addAction(reset_act);
mywidget->setContextMenuPolicy(Qt::ActionsContextMenu);
// here connect the 'triggered' signal to some slot
For Qt3, you might have to intercept the context menu event, and thus inherit the QSpinBox and others. Or maybe you can intercept the context menu event from the main window, detect if it occurred above the widget supposed to have a context menu (using the QWidget::childAt method) and show it there. But you'll have to test.
For Qt4, you can do this for an editable QComboBox by using your own QLineEdit. Create a derived QLineEdit class which implements the contextMenuEvent
class MyLineEdit : public QLineEdit
{
Q_OBJECT
public:
MyLineEdit(QWidget* parent = 0) : QLineEdit(parent){}
void contextMenuEvent(QContextMenuEvent *event)
{
QPointer<QMenu> menu = createStandardContextMenu();
//add your actions here
menu->exec(event->globalPos());
delete menu;
}
};
Then, use the setLineEdit function of QComboBox to set the line edit
MyLineEdit* edit = new MyLineEdit();
comboBox->setLineEdit(edit);
The combo box will now use your line edit class. The createStandardContextMenu function creates the normal context menu and you can add any new actions to it that you like in the contextMenuEvent handler before it is shown.
If the QComboBox is not editable then it doesn't have a default context menu so using the Qt::ActionsContextMenu method is much simpler.
QAbstractSpinBox also has a setLineEdit function so you can use a similar technique. Although, for some reason the setLineEdit function is protected on QAbstractSpinBox but public on QLineEdit.

Resources