0

I have displayed in a QListWidget several features ranked according to their values from a field named "CODE". Based on this list I would like to select a feature and after a click on a QpushButton to zoom to the extent of this feature in the canvas.

Here is my crude attempt (I am still a beginner):

def append_features_to_QlistWidget (self): #associated to QpushButton_1

    #----------------function sample--------------------

    self.layer = QgsProject.instance().mapLayersByName('my_layer')[0]

    self.selection = []

    for self.feat in self.layer.getFeatures():
        self.attrs = self.feat.attributes()
        self.code= self.attrs[0]
        self.selection.append(self.code)
   
    self.dlg.listWidget.addItems(self.selection)
            
    
def zoom (self): #associated to QpushButton_2
    
    inds = [i.text() for i in self.dlg.listWidget.selectedItems()]
    
    attribute_value = {}
    
    for i in inds:
        attribute_value[i] = [f for f in self.layer.getFeatures() if f["code"] == i][0]
    
    self.layer.selectByIds(attribute_value)
           
    iface.mapCanvas().zoomToSelected(self.layer)
    

    ##Other incomplete attempt:
    # ids = [i.id() for i in self.selection] 
    # self.layer.selectByIds(ids)
    #iface.mapCanvas().zoomToSelected(self.layer)

1 Answer 1

2

Something like the code below should work (I simplified, cleaned up a bit and added small features) :

class MyQgsWidget(QWidget):

    def __init__(self, lyr_name: str, parent=None):
        super(MyQgsWidget, self).__init__(parent)
        self.vertical_layout = QVBoxLayout()
        self.setLayout(self.vertical_layout)
        self.list_widget = QListWidget(self)
        self.zoom_pushbutton = QPushButton("Zoom !", self)
        self.vertical_layout.addWidget(self.list_widget)
        self.vertical_layout.addWidget(self.zoom_pushbutton)
        self.layer = QgsProject.instance().mapLayersByName(lyr_name)[0]
        self.layer_feats = []
        self.zoom_pushbutton.clicked.connect(self.zoom)
        self.list_widget.itemDoubleClicked.connect(self.zoom)
        self.load_layer_feats()

    def load_layer_feats(self):
        self.layer_feats = [
            (feat.id(), str(feat.attribute("code"))) for feat in self.layer.getFeatures()
        ]
        self.list_widget.addItems([code for _, code in self.layer_feats])

    def zoom(self):
        sel_ids = [
            featid for featid, code in self.layer_feats if code == self.list_widget.currentItem().text()
        ]
        self.layer.removeSelection()
        self.layer.select(sel_ids)
        iface.mapCanvas().zoomToSelected(self.layer)


w = MyQgsWidget("my_layer")
w.show()
5
  • Awesome ! Merci beaucoup :) ! Could you just clarify why did you add for _, and featid for featid since we don't use it afterwards ?
    – wanderzen
    Mar 5, 2021 at 7:58
  • 1
    code for _, code: we just want to have a list of codes, so we don't need feature ID (_). featid for featid, code in self.layer_feats: we want a list of features ID, so featid is mandatory here and code because we used it in the condition if code == self.list_widget.currentItem().text(). Mar 5, 2021 at 8:15
  • Ok thanks for the explanation ! But I was just wondering why we have to use featid instead of feat.id() ?
    – wanderzen
    Mar 5, 2021 at 8:28
  • I just created a smaller subset of layer features data in self.layer_feats that is a list of features IDs and "code" field values. So, I think it's faster to iterate (but I don't speedtest it with self.layer.getFeatures()). Mar 5, 2021 at 8:34
  • Aaaah got it now ! Thanks !
    – wanderzen
    Mar 5, 2021 at 8:56

Your Answer

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

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