Page 6 sur 25
Affichage personnalisé des attributs
Un autre exemple de sélection spécifique, avec 3 fonctions séparées, dont une pour afficher les attributs de la couche dans un dock personnalisé.
Imaginez que vous ayez un projet QGIS avec de grosses couches, beaucoup d'entités, beaucoup de champs... ce qui rend votre projet peu lisible.
Ces couches sont liées entre elles par un champ id. Il est alors possible de conditionner l'affichage des entités d'une couche sur un clic d'une entité d'une autre couche.
Le code suivant va zoomer sur l'entité cliquée, afficher certains de ses attributs, certains des attributs de la couche liée et masquer les autres entités de la couche liée.
from qgis.PyQt.QtWidgets import QDockWidget, QTextEdit from qgis.PyQt.QtCore import Qt, QTimer layerA = QgsProject.instance().mapLayersByName("Ma couche A")[0] layerB = QgsProject.instance().mapLayersByName("Ma couche B")[0] # Cacher B par défaut layer_tree = QgsProject.instance().layerTreeRoot().findLayer(layerB.id()) if layer_tree is not None: layer_tree.setItemVisibilityChecked(False)
# Dock d'affichage dock = QDockWidget("Attributs de la couche A", iface.mainWindow()) dock.setAllowedAreas(Qt.LeftDockWidgetArea | Qt.RightDockWidgetArea) text_edit = QTextEdit() text_edit.setReadOnly(True) dock.setWidget(text_edit) iface.addDockWidget(Qt.RightDockWidgetArea, dock) dock.hide()
# Fonction affichage des attributs def displayAttributes(features, layer): if not features: dock.hide() return feat = features[0] attrs = feat.attributes() fields = layer.fields() data = {field.name(): attrs[i] for i, field in enumerate(fields)} groupsFields = { "ID": {"id_a": "ID A", "foreign_key_layer_b": "Clé B"}, \ "Bla bla bla...": {"area": "Surface", "len": "Longueur"}, \ "Bla bla bla...": {"blablafield": "Igo", "anotherblablafield": "Wesh"}} used_fields = set() msg = "" for titre, champs in groupsFields.items(): msg += f"{titre}" for champ, label in champs.items(): valeur = data.get(champ, "–") msg += f"- {label}: {valeur}" used_fields.add(champ) msg += "BR" autres_champs = [k for k in data.keys() if k not in used_fields] if autres_champs: msg += "Champs restants" for champ in autres_champs: msg += f"- {champ}: {data[champ]}" text_edit.setHtml(msg) dock.show()
# Fonction zoom def zoom_after_delay(): matching_features = list(layerB.getFeatures()) if not matching_features: return extent = matching_features[0].geometry().boundingBox() for f in matching_features[1:]: extent.combineExtentWith(f.geometry().boundingBox()) if extent.isEmpty(): return extent_buffered = extent.buffered(extent.width() * 0.1) iface.mapCanvas().setExtent(extent_buffered) iface.mapCanvas().refresh() iface.mapCanvas().update()
# Fonction filtre def custom_filter(): selected_features = layerA.selectedFeatures() displayAttributes(selected_features, layerA) if not selected_features: layerB.setSubsetString("") if layer_tree is not None: layer_tree.setItemVisibilityChecked(False) return # Filtrer "Ma couche B" à partir de "Ma couche A" id_cads = [f['foreign_key_layer_b'] for f in selected_features] if len(id_cads) == 1: expr = f"id_b = '{id_cads[0]}'" else: id_cads_str = ", ".join(f"'{id}'" for id in id_cads) expr = f"id_b IN ({id_cads_str})" layerB.setSubsetString(expr) if layer_tree is not None: layer_tree.setItemVisibilityChecked(True) QTimer.singleShot(50, zoom_after_delay)
layerA.selectionChanged.connect(custom_filter)