QT: Context menu (QMenu) reference from the QTableWidget - qt

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);
}

Related

Assigning actions to QMenu items

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);.

How to add custom QWidget to the QMenubar as action which can be toggled?

I have an Widget class as a QtPlugin. In my main application i want to load this widget and add to menubar as toggledaction, so that later if i close the widget i can open it via the Menu bar. How can this be achieved.
As this is not a docketwidget i cannot use the following:
ui->menuPlugins->addAction(dockedWidget->toggleViewAction());
I have tried something like this:
void MainWindow::addToPluginsMenu(QWidget *const widget) {
ui->menuPlugins->setEnabled(true);
QWidgetAction *ac = new QWidgetAction(this);
ui->menuPlugins->addAction(ac);
}
An action is added but it is empty and cannot be toggled. Could anyone provide me a solution?
Thank you
In order to add toggled actions and keep them visible after an action is toggled.
Use the setDefaultWidget function
For example:
// Create menu
QMenu * poMainMenu = new QMenu(this);
// toggled widget
QCheckBox * poCbTest = new QCheckBox("toggle",this);
// set the toggle widget as menu action
QWidgetAction *ac = new QWidgetAction(this);
ac->setDefaultWidget(poCbTest);
// add the action to the menu
poMainMenu->addAction(ac);

How to handle actions from context menu of a QLineEdit in Qt?

I would like to intercept the paste action of a QLineEdit context menu that is created by default in any QLineEdit widget (see picture below)
Is there a way to redirect the Paste action of the context menu by any means?
One can fiddle with the actions in the context menu by overloading the contextMenuEvent of the QLineEdit widget.
Edit:
The code of the link above:
void LineEdit::contextMenuEvent(QContextMenuEvent *event)
{
QMenu *menu = createStandardContextMenu();
menu->addAction(tr("My Menu Item"));
//...
menu->exec(event->globalPos());
delete menu;
}
And the code that I actually used for my purposes:
menu = self.createStandardContextMenu()
menu.actions()[5].connect(self.paste) # The hard ref to the 6th item is not ideal but what can you do...
menu.exec_(event.globalPos())

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'
}

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