11
votes

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?

4

4 Answers

25
votes

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

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.

7
votes

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:

enter image description here

2) Create Handler function

In designer, right click on the treeWidget and select "Go to Slot..." option. A window similar to this will appear:

enter image description here

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.

enter image description here

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 :

enter image description here

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.

enter image description here

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
}
2
votes

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