2017-09-05 2 views
0

Je suis actuellement en train de développer un plugin pour QGIS avec Python 2.7 et PyQt 4. Mon plugin devrait avoir une liste vérifiable de couches de cartes (liste d'éléments non pertinentes) qui serait régénérée chaque fois que l'utilisateur ouvre l'onglet Paramètres . Bien que j'ai réussi à créer une liste vérifiable de QCheckBoxes qui régénère chaque fois que je clique sur le bouton Paramètres, il est encore loin d'être bon et fonctionnel. Comme je l'ai compris, mon problème est principalement la relation parent-enfant et la suppression de la mise en page.Liste QCheckBox dynamiquement modifiable

self.layers = qgis_api.get_layers() 
    #ScrollArea setup 
    if (api.selected_upload_layers == [] and 
     api.project.layerTreeRoot().children() != []): 
     self.tmp_layers = qgis_api.get_layers() 
     self.layout = QVBoxLayout(self.settingsDock.groupBox) 
     self.scroll = QScrollArea() 
     self.layout.addWidget(self.scroll) 
     self.scroll.setWidgetResizable(True) 
     self.scroll.setFixedHeight(111) 
     self.scrollContent = QWidget(self.scroll) 
     self.scrollLayout = QVBoxLayout(self.scrollContent) 
     self.scrollContent.setLayout(self.scrollLayout) 
     self.scroll.setWidget(self.scrollContent) 

    i = 0 
    self.checkboxes = [] 
    for layer in self.layers: 
     self.checkboxes.append(QCheckBox("{0}".format(layer.name()))) 
     self.checkboxes[i].stateChanged.connect(lambda checked, i = i : self.cBoxChecked(self.checkboxes[i])) #inverts logic if run every time 
     # check logic 
     if i < len(self.layers)-1: 
      i += 1 
    # Create checkboxes first time 
    if not api.upload: #api.upload becomes true when clicked save in settings 
     for i in range(0, len(self.layers)): 
      try: 
       self.scrollLayout.addWidget(self.checkboxes[i]) 
       self.checkboxes[i].setChecked(True) 
      except Exception as e: 
       print str(e) 
    # compare layer list at creation and now to notice difference 
    elif self.tmp_layers != self.layers: 
     for i in range(0, self.scrollLayout.count()): 
      self.scrollLayout.removeItem(self.scrollLayout.itemAt(0)) 
      try: # delete old layer items 
       for i in range(0, len(self.layers)): 
        self.scrollLayout.addWidget(self.checkboxes[i]) 
        self.checkboxes[i].setChecked(True) 
      except Exception as e: 
       print str(e) 

Fonction cBoxChecked() est la suivante:

def cBoxChecked(self, cBox): 
    """ Add functionality to ScrollArea checkboxes.""" 
    if cBox.isChecked(): 
      if cBox.text() not in api.selected_upload_layers: 
       api.selected_upload_layers.append(cBox.text()) 
    else: 
      try: 
       api.selected_upload_layers.remove(cBox.text()) 
      except Exception as e: 
       print str(e) 

alhtough maintenant je ne reçois aucune exception, et la liste est régénérés. Je remarque l'ancienne liste sous la nouvelle, ce qui signifie que je ne supprime pas la mise en page correctement (il y a plusieurs questions pour la suppression de la mise en page) mais je ne pouvais pas la comprendre complètement. Résumer. Quel est le moyen le plus commode de détruire et de recréer la mise en page et de comprendre les relations QObject parent-enfant dans cet exemple concret? Et une autre question qui me dérange est que, à chaque nouvelle ouverture de l'onglet des paramètres, il semble y avoir une réverbération logique dans la fonction lambda qui fait tout le poids pour sélectionner certains CheckBox. Comment réparer ça? Merci pour votre temps :)

Répondre

0

Je l'ai réparé. Le principal problème était la méthode removeItem qui n'a pas fonctionné comme prévu. Bien que le tout était un gâchis. Ce que j'ai fait maintenant? J'ai créé une liste de cases à cocher lors de l'initialisation de la classe en tant que liste vide et avec les bonnes conditions que je vérifie est la première fois que le SettingsDock est appelé, ou est-il invoqué après quelque chose a changé dans la liste d'interface de couche. Le code est comme suit. Si quelque chose ne s'explique pas correctement dans les commentaires, n'hésitez pas à demander pourquoi je l'ai fait de cette façon. Vive

self.layers = qgis_api.get_layers() 
    reduced_layers = [] 
    # reduced_layers is list variable which is populated with all layers 
    # without redundant ones (same names of multiple files .shp/.shx/.dbf) 
    # shapefile file format 
    for layer in self.layers: 
     if layer.name() not in reduced_layers: 
      reduced_layers.append(layer.name()) 

    # ScrollArea setup 
    # Set up settingsDock.groupBox as a parent of Vertical layout 
    # Check if Settings was clicked before api.upload would be handy for 
    # that, scroll is QScrollArea and is added as widget with layout as 
    # parent, after that I set up Scroll Content as widget with scroll 
    # as parent, while scroll Layout is Vertical layout with scrollContent 
    # as parent, but then i use scroll.setWidget method to define it as 
    # a parent to scrollContent 
    if (api.selected_upload_layers == [] and 
     api.project.layerTreeRoot().children() != []): 
     self.tmp_layers = qgis_api.get_layers() 
     self.layout = QVBoxLayout(self.settingsDock.groupBox) 
     self.scroll = QScrollArea() 
     # self.layout.addWidget(self.scroll) 
     self.scroll.setWidgetResizable(True) 
     self.scroll.setFixedHeight(111) 
     self.layout.addWidget(self.scroll) 
     self.scrollContent = QWidget(self.scroll) 
     self.scrollLayout = QVBoxLayout(self.scrollContent) 
     self.scroll.setWidget(self.scrollContent) 

    # As self.checkboxes are initialized as empty list, here are we 
    # generating a list of QCheckBox items with layer names(if there are 
    # multiple layers with same name(shapefile format), only one will be 
    # added as checkbox 
    # After generating checkboxes list we use it to populate widgets, 
    # QCheckBoxes in ScrollLayout, and set it in default as Checked 
    # This is basically 1st time initialization 
    if self.checkboxes == []: 
     try: 
      for i in range(0, len(self.layers)): 
       if self.layers[i].name() not in map(lambda x: x.text(), 
                self.checkboxes): 
        self.checkboxes.append(QCheckBox('{}'.format(
              self.layers[i].name()))) 
      for i in range(0, len(self.checkboxes)): 
       self.scrollLayout.addWidget(self.checkboxes[i]) 
       self.checkboxes[i].setChecked(True) 
       api.selected_upload_layers = map(lambda x: x.text(), 
               self.checkboxes) 
     except Exception as e: 
      print str(e) 

    # if checkboxes are different from layer list (that is generated) in 
    # the moment of clicking show settings which basically indicates that 
    # interface layer list has been chaged, we must update checkboxes 
    # To update checkboxes list it's firstly deleted with ScrollContent 
    elif map(lambda x: x.text(), self.checkboxes) != reduced_layers: 
     num = self.scrollLayout.count() 
     self.scrollLayout.removeWidget(self.scrollContent) 
     self.scrollContent.deleteLater() 
     self.scrollContent = QWidget(self.scroll) 
     self.scrollLayout = QVBoxLayout(self.scrollContent) 
     self.scroll.setWidget(self.scrollContent) 
     try: 
      self.checkboxes = [] 
      for i in range(0, len(self.layers)): 
       if self.layers[i].name() not in map(lambda x: x.text(), self.checkboxes): 
        self.checkboxes.append(QCheckBox('{}'.format(
              self.layers[i].name()))) 
      for i in range(0, len(self.checkboxes)): 
       self.scrollLayout.addWidget(self.checkboxes[i]) 
       self.checkboxes[i].setChecked(True) 
     except Exception as e: 
      print (e) 

    for i in range(0, len(self.checkboxes)): 
     self.checkboxes[i].stateChanged.connect(lambda checked, i=i: 
              self.checkBoxChecked()) 

Fonction checkBoxChecked() est la suivante:

def checkBoxChecked(self): 
    """Add functionality to ScrollArea checkboxes.""" 
    #print api.selected_upload_layers 
    indices = [] 
    for i in range(0, len(self.checkboxes)): 
     if self.checkboxes[i].isChecked(): 
      # print cBox.isChecked() 
      print self.checkboxes[i].text() + " is selected" 
      indices.append(i) 
     else: 
      print self.checkboxes[i].text() + " is deselected" 

    api.selected_upload_layers = [map(lambda x: x.text(), self.checkboxes)[i] for i in indices]