I was able to create a context menu for my QTreeWidget as below
QMenu* pContextMenu = new QMenu(this)
QTreeWidget* pTreeWidget = new QTreeWidget();
QAction* pOpenFile = new QAction(tr("Open A File"), pContextMenu);
pTreeWidget->setContextMenuPolicy(Qt::ActionsContextMenu);
pTreeWidget->addAction(pOpenFile);
But I want a different popup for a branch than a leaf. How do I assign a different popup depending on the type of widgetitem clicked?
My tree:
- Branch1 <– Popup1
- Leaf1
- Leaf2 <– Popup2
- Branch2
- Branch3
- Leaf1
- Branch3
QWidget::actions() is not listed as virtual. Else I would have derived my own class from QTreeWidget & reimplemented actions().
Method 1: Override QTreeWidget
A context menu assigned to the
QTreeWidgetitself will not let you have different context menus for different items, as you have discovered.As the Qt item views don’t have special API for context menus, you have to implement this yourself. Fortunately, it’s not very difficult; you just need to:
QTreeWidget.customContextMenuRequested(const QPoint&)signal to a custom slot.I’ve posted a complete working example. Some details to note include:
QTreeWidgetItemprovides a handytypeproperty to let you identify items easily without casting, string parsing, or other awkward/fragile methods.Custom
QTreeWidgetItemtype values should be greater than or equal toQTreeWidgetItem::UserType.When displaying a context menu, you must pass a global position to
exec(). To correctly map from a position in the widget’s space in the slot, you must use the item’s viewport widget.Method 2: Override QItemDelegate (and QTreeWidget …)
An alternate method is to implement your own
QAbstractItemDelegatesubclass, and assign it to your tree widget. In your item delegate, you can overrideeditorEvent()to handle mouse presses in the same way.Although this approach frres is actually more in line with Qt’s item view API design, there are a few key disadvantages to this approach:
Item delegates use
QModelIndexobjects to represent items. To convert to aQTreeWidgetItem, you must use theQTreeWidget::itemFromIndex()method. Unfortunately, this is protected, so it will actually require you to subclassQTreeWidgetanyway to provide this API for your delegate. This adds some more boilerplate complexity to your code.The
editorEvent()hook is invoked before the item view handles the event. This means that you can’t easily display a context menu and allow the default behavior at the same time (such as selecting the item that was right-clicked).Since the
editorEvent()handler sees all kinds of different events, you must be even more careful to handle them correctly. You must also be careful not to let this monolithic handler grow out of control if your behaviors are complicated.The core code is very similar, but again, there’s a bit more boilerplate. I’ve posted an example of this approach, as well.