1

I'm working on a QGIS3 plugin and having problems deleting layers (from previous run of the plugin) from the main interface. I have two layers - a user supplied input polygon file and a plugin generated output polygon file. It works the first time I run it, and loads the layers as expected. However, when I try to run interface_clean() to remove the previous versions of the layers, I get

[2019-06-10 16:01:13.503881] font color="orange"[warn] Could not load selection in layer

[2019-06-10 16:01:13.534769] font color="red"[Unexpected error] File "change_mapper.py", line 790, in run self.interface_clean()

Followed by a class RuntimeError

wrapped C/C++ object of type QgsVectorLayer has been deleted

The layer names disappears from the Layers Tab but the vectors are continuing still to be visible in the display. I assume I am making a horrible error in my coding.

Can anyone help?

To display vector objects

def display_input_vector_object(self):

    # Load vector object into main window
    QgsProject.instance().addMapLayer(self.vector_file_obj)

    # Set layer colour to be purple
    layer = self.iface.activeLayer()
    single_symbol_renderer = layer.renderer()
    symbol = single_symbol_renderer.symbol()
    symbol.setColor(QColor(142,0,142,85))
    layer.triggerRepaint()
    self.iface.layerTreeView().refreshLayerSymbology(layer.id())


def display_final_vector_object(self):

    self.current_layer = self.iface.addVectorLayer(self.out_vectorFilename, self.displayName, "ogr")
    if not self.IndexIncrease:
        land_class = {                                                              # Create dictionary to store 'attribute value' : ('symbol colour', 'legend name')
            '0': ('#0f0', ''),
            '1': ('#ff0000', 'Significant Negative Change')
        }
    else:
        land_class = {                                                              # Create dictionary to store 'attribute value' : ('symbol colour', 'legend name')
            '0': ('#0f0', ''),
            '1': ('#00ff00', 'Significant Positive Change')
        }

    categories = []                                                             # Create list to store symbology properties
    for classes, (color, label) in land_class.items():                          # Iterate through the dictionary
        symbol = QgsSymbol.defaultSymbol(self.current_layer.geometryType())          # Automatically set symbols based on layer's geometry
        symbol.setColor(QColor(color))                                          # Set colour
        if classes == '0':                                                      # Set symbol with value = 0 to be transparent
            symbol.setOpacity(0)
        category = QgsRendererCategory(classes, symbol, label)                  # Set the renderer properties
        categories.append(category)

    expression = 'DN'                                                           # Field name 
    renderer = QgsCategorizedSymbolRenderer(expression, categories)             # Set the categorized renderer
    self.current_layer.setRenderer(renderer)
    self.current_layer.triggerRepaint()                                              # Refresh layer

To clear vector objects

def interface_clean(self):

    # Check for any previous versions of files in interface.

    layers = [layer for layer in QgsProject.instance().mapLayers().values()]
    for layer in layers:
        if (layer.type() == QgsMapLayer.VectorLayer):
            if (layer.name() == "User selected input polygons"):
                QgsProject.instance().removeMapLayer(layer)
            if (self.displayName in layer.name()):
                QgsProject.instance().removeMapLayer(layer)

I do not understand why I am getting a complaint about loading files when I'm trying to remove them.

Can anyone see anything obvious that I am missing?

3
  • Taking a bit of a guess here... How are you calling your interface_clean function? Is it by any chance from a button in your plugin dialog? If so, make sure to connect the button.clicked signal to your function slot in the initGui method NOT the run method. Connecting signals to slots in the run method without disconnecting them is a likely source of deleted C++ object errors.
    – Ben W
    Jun 11 '19 at 2:21
  • Hi Ben, Thank you for the suggestion. I am calling interface_clean() directly from the run method. It is not connected to any of the gui. Are you saying it would be better in initGui?
    – SJJ
    Jun 11 '19 at 10:33
  • No, it was just unclear how it was being called. I thought you might have had a signal/ slot connection in the run method which was not being disconnected. The problem is not obvious to me. Someone else may know. Posting more of your code may help too.
    – Ben W
    Jun 11 '19 at 12:43
1

Ahh - I found the problem. In interface_clean() I made mistake with the code. It should read

def interface_clean(self):

    layers = [layer for layer in QgsProject.instance().mapLayers().values()]
    print(' Checking existing layers in interface for unwanted files')
    print('displayName is ',self.displayName)
    for layer in layers:
        if (layer.type() == QgsMapLayer.VectorLayer):
            print('layer name is : ',layer.name())
            if (layer.name() == "User selected input polygons" or self.displayName in layer.name()):
                QgsProject.instance().removeMapLayer(layer)

The original version was crashing as, in second if clause, it was looking for a layer that had already been deleted in the first if clause. Stupid mistake on my part. Fixed now.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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