4

In the layer tree, I want to move a few layers at root level to a group also at root level. From what I have gathered so far, I have to clone the layer first, add it to the group and then delete the original layer.

https://docs.qgis.org/3.4/en/docs/pyqgis_developer_cookbook/cheat_sheet.html#advanced-toc

So I am trying to fill the variables with the group and layers I want to work with. The for-loop finds the group, but for some reason, I am getting None for the value of LyrOne.

from qgis.core import QgsLayerTreeGroup, QgsLayerTreeLayer
root = QgsProject.instance().layerTreeRoot()

for child in root.children():
    if isinstance(child, QgsLayerTreeGroup):
        print ("- group: " + child.name())
    elif isinstance(child, QgsLayerTreeLayer):
        print ("- layer: " + child.name())

grpQS = root.findGroup("QS")
LyrOne = root.findLayer("One")
print(QS_group)
print(LyrOne)

The results of the for-loop and the print statements are:

- layer: One
- group: QS
<qgis._core.QgsLayerTreeGroup object at 0x0000000008032A68>
None

Why can I get a reference to the group, but not for the layer?

EDIT: I managed to create a dictionary with the names of the layers as keys

dictLayer = {}
for child in root.children():
    if isinstance(child, QgsLayerTreeLayer):
        lyrName = child.name()
        lyrID = child.layerId()
        dictLayer[lyrName] = lyrID

LyrOne = dictLayer["One"]

Unfortunately, this solution Add layer to a QGIS group using Python

toc = self.iface.legendInterface()
groups = toc.groups()
groupIndex = groups.index(u'myGroup')
toc.moveLayer(newLayer, groupIndex)

doesn't work in QGIS3. How can I move a layer to a group in QGIS 3?

GISme
  • 441
  • 1
  • 3
  • 13

1 Answers1

7

If you look at the API, the findGroup() method need a String "name value" but findLayer() need a Layer Id not the name.

Then to make it work you need this:

from qgis.core import QgsLayerTreeGroup, QgsLayerTreeLayer
root = QgsProject.instance().layerTreeRoot()

for child in root.children():
    if isinstance(child, QgsLayerTreeGroup):
        print ("- group: " + child.name())
    elif isinstance(child, QgsLayerTreeLayer):
        print ("- layer: " + child.layerId())

Move Loaded layer:

layer = QgsProject.instance().mapLayersByName(<layer_name>)[0]
root = QgsProject.instance().layerTreeRoot()

mylayer = root.findLayer(layer.id())
myClone = mylayer.clone()
parent = mylayer.parent()

group = root.findGroup(<group_name>)
group.insertChildNode(0, myClone)

parent.removeChildNode(mylayer)

Load layer in a specific group

layer = QgsVectorLayer(<layer_path>, "airports", "ogr")

QgsProject.instance().addMapLayer(layer, False)

root = QgsProject.instance().layerTreeRoot()
g = root.findGroup(<group_name>)
g.insertChildNode(0, QgsLayerTreeLayer(layer))
Fran Raga
  • 7,838
  • 3
  • 26
  • 47
  • Ok, got it. My problem is, that the script needs to work with different layer trees, so the IDs may be different. The only sure reference is the name of the layer. Is there a way to to get a reference to a layer with its name? – GISme Jul 22 '19 at 14:30
  • I updated my question with my progress. – GISme Jul 22 '19 at 15:08
  • The cloning of my layer LyrOne with LyrOne_clone = LyrOne.clone() doesn't work :( – GISme Jul 22 '19 at 15:33
  • Your initial question wasn't that! To move layer to group is duplicated – Fran Raga Jul 22 '19 at 15:45
  • I hope this is not as frustrating for you as it is for me. The possible duplicate does not have a check mark beside the answer, because the person had the same problem: the layer is already there, it doesn't need to be loaded. The layer just needs to be moved to a different group. So does this mean I cannot ask the same question, if there wasn't a suitable answer? – GISme Jul 22 '19 at 15:57
  • I updated my answer – Fran Raga Jul 22 '19 at 16:29
  • I tried the approach "Move Loaded Layer" and put a print statement after each line. For layer I got <qgis._core.QgsVectorLayer object at 0x00000000193D2678> For root I got <qgis._core.QgsLayerTree object at 0x00000000080324C8> For mylayer I got None. So the rest of the code doesn't work, because AttributeError: NoneType object has no attribute clone – GISme Jul 23 '19 at 07:24
  • If mylayer is None, you are not using well root.findLayer(layer.id()) then. This code is tested with QGIS 3.8 and works perfectly – Fran Raga Jul 23 '19 at 07:40
  • I think I found the problem: The layers with the "None" result were generated through a model. They are temporary layers ('memory'). Should I ask a new question: How to move temporary layers in the LayerTree? – GISme Jul 23 '19 at 08:19
  • This code also works with memory layers! Tested in QGIS 3.8 – Fran Raga Jul 23 '19 at 08:42