5

I am using the script below to display an icon next to my layer in the layer tree view, which works fine. However, when a user moves the position of that node, the indicator disappears.

layer1 = QgsVectorLayer("Point?crs=EPSG:4326", "my layer", "memory")
QgsProject.instance().addMapLayer(layer1, False)

root = QgsProject.instance().layerTreeRoot()
node_layer1 = root.addLayer(layer1)

indicator = QgsLayerTreeViewIndicator(iface.layerTreeView())
indicator.setToolTip('Test')
indicator.setIcon(QIcon(':/images/themes/default/mActionIdentify.svg'))
indicator.clicked.connect(lambda: print('indicator clicked'))

iface.layerTreeView().addIndicator(node_layer1, indicator)

How would I preserve the indicator and the connected action, so that it can be triggered even after moving the node?

Some context on what I additionally tried so far:

I tried to listen for the QAbstractItemModel.rowsMoved signal, to identify when the node is moved and then again re-add the indicator afterwards.

But it seems that only this specific signal is not emitted by QgsLayerTreeModel.

Another thing I tried is listening to the rowsInserted signals to detect if my created node has been inserted at a different position, in order to then again re-add the indicator. But that also does not work, because on moving the node the original object gets deleted. So if I try to add the indicator with iface.layerTreeView().addIndicator(node_layer1, indicator) it complains about a

RuntimeError: wrapped C/C++ object of type QgsLayerTreeLayer has been deleted

1 Answer 1

4

I was able to get it working with the code below:

layer1 = QgsVectorLayer("Point?crs=EPSG:4326", "my layer", "memory")
QgsProject.instance().addMapLayer(layer1, False)

root = QgsProject.instance().layerTreeRoot()
node = root.addLayer(layer1)

indicator = QgsLayerTreeViewIndicator(iface.layerTreeView())
indicator.setToolTip('Test')
indicator.setIcon(QIcon(':/images/themes/default/mActionIdentify.svg'))
indicator.clicked.connect(lambda: print('indicator clicked'))

view = iface.layerTreeView()

view.addIndicator(node, indicator)

def rows_inserted(parent, first, last):
    nodes = root.findLayers()
    for n in nodes:
        if n.layer().id() == layer1.id():
            if not view.indicators(n):
                view.addIndicator(n, indicator)

conn = view.layerTreeModel().rowsInserted.connect(rows_inserted)

After removing layer, clean up by disconnecting signal/slot and deleting indicator object:

QObject.disconnect(conn)
del indicator

Screencast shows this working:

enter image description here

Based very loosely on source code in qgslayertreeviewindicatorprovider.cpp which would probably take care of this nicely but does not seem to be exposed in the Python API bindings.

2
  • 1
    Well done, Ben W. Commented Dec 2, 2021 at 12:03
  • 1
    @Germán Carrillo, thank you! :-)
    – Ben W
    Commented Dec 2, 2021 at 14:00

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.