Page 6 sur 24
Affichage personnalisé des attributs
Un autre exemple avec 3 fonctions séparées, dont une pour afficher les attributs de la couche dans un dock personnalisé.
Vous avez de grosses couches, ou plutôt des couches avec énormément d'entités, beaucoup de champs... ce qui rend votre projet peu lisible.
Ces couches sont liées entre elles par id. Il est 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 va masquer les entités tierces, puis les filtrer et enfin zoomer sur l'entité cliquée, tout en affichant certains de ses attributs.
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)