0

I am having some difficulties in adding a layer to my canvas or even to main project. I create a plugin in QGIS 3.10. This plugin has a table of contents and a canvas to open some maps. I search and find this code:

 # display file in canvas
fileCI = diretory to my shapefile
file_info_norm = QFileInfo(str(fileCI))

# vector layer
vlayer = QgsVectorLayer(fileCI, file_info_norm.fileName(), 'ogr')

if not vlayer.isValid():
    return

QgsProject.instance().addMapLayer(vlayer)
self.canvas.setExtent(vlayer.extent())

However my QGIS always crashes when I run my code. I cannot see why this happens.

I create a widget in Qt Designer and promote to QgsMapCanvas.

Then in dialog in init function I create these lines of code:

self.canvas = QgsMapCanvas()
self.canvas.setCanvasColor(QColor(255, 255, 255))
self.canvas.setCanvasColor(Qt.white)
self.canvas.enableAntiAliasing(True)
self.setCentralWidget(self.canvas)

And then I define the lines above. The shapefile is added to the QGIS canvas but not to my QWidget promoted to QgsMapCanvas. The shapefile is a point shapefile in EPSG: 3763 coordinate system.

My dialog code is:

import os

from qgis.PyQt import uic
from qgis.PyQt import QtWidgets
from qgis.core import *
from qgis.gui import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *


# This loads your .ui file so that PyQt can populate your plugin with the elements from Qt Designer
FORM_CLASS, _ = uic.loadUiType(os.path.join(
    os.path.dirname(__file__), 'coal_mine_dialog_base.ui'))


class PluginDialog(QtWidgets.QMainWindow, FORM_CLASS):
    def __init__(self, parent=None):
        """Constructor."""
        super(PluginDialog, self).__init__(parent)
        # Set up the user interface from Designer through FORM_CLASS.
        # After self.setupUi() you can access any designer object by doing
        # self.<objectname>, and you can use autoconnect slots - see
        # http://qt-project.org/doc/qt-4.8/designer-using-a-ui-file.html
        # #widgets-and-dialogs-with-auto-connect

        self.canvas = QgsMapCanvas()
        self.layers = []
        self.canvas.setCanvasColor(QColor(255, 255, 255))
        self.canvas.setCanvasColor(Qt.white)
        self.canvas.enableAntiAliasing(True)
        self.setCentralWidget(self.canvas)
        self.initialize_map()




        self.actionZoomIn = QAction("Zoom in", self)
        self.actionZoomOut = QAction("Zoom out", self)
        self.actionPan = QAction("Pan", self)

        self.actionZoomIn.setCheckable(True)
        self.actionZoomOut.setCheckable(True)
        self.actionPan.setCheckable(True)

        self.actionZoomIn.triggered.connect(self.zoomIn)
        self.actionZoomOut.triggered.connect(self.zoomOut)
        self.actionPan.triggered.connect(self.pan)

        self.toolbar = self.addToolBar("Canvas actions")
        self.toolbar.addAction(self.actionZoomIn)
        self.toolbar.addAction(self.actionZoomOut)
        self.toolbar.addAction(self.actionPan)

        # create the map tools
        self.toolPan = QgsMapToolPan(self.canvas)
        self.toolPan.setAction(self.actionPan)
        self.toolZoomIn = QgsMapToolZoom(self.canvas, False)  # false = in
        self.toolZoomIn.setAction(self.actionZoomIn)
        self.toolZoomOut = QgsMapToolZoom(self.canvas, True)  # true = out
        self.toolZoomOut.setAction(self.actionZoomOut)

        self.pan()



        self.root = QgsProject.instance().layerTreeRoot()
        self.bridge = QgsLayerTreeMapCanvasBridge(self.root, self.canvas)
        self.model = QgsLayerTreeModel(self.root)
        self.model.setFlag(QgsLayerTreeModel.AllowNodeReorder)
        self.model.setFlag(QgsLayerTreeModel.AllowNodeRename)
        self.model.setFlag(QgsLayerTreeModel.AllowNodeChangeVisibility)
        self.model.testFlag(QgsLayerTreeModel.ShowLegend)
        self.model.setFlag(QgsLayerTreeModel.ShowLegendAsTree)
        self.view = QgsLayerTreeView()
        self.view.setModel(self.model)
        # QMessageBox.about(self,'teste',str(self.view))

        self.createLegendWidget()  # Create the legend widget
        provider = MyMenuProvider(self.view, self.canvas)
        # QMessageBox.about(self,'teste',str(self.view.currentLayer()))
        self.view.setMenuProvider(provider)

        self.setupUi(self)

I only adapt the code to the original code created by QtDesigner.

  • Instead of QgsProject.instance().addMapLayer(vlayer), try this one self.canvas.setLayers([vlayer]) – J. Monticolo Jan 29 at 12:30
  • I also try with that line. It crashes again. This little piece of code in the main script of the plugin. However I change to the dialog script and part of it works. However, it only opens in QGIS canvas and not in my personal canvas, even if I put two more lines such as: self.canvas.setExtent(vlayer.extent()) self.canvas.setLayers([vlayer]) – Bárbara Duarte Jan 29 at 12:36
  • 1
    I think we need to see how you code your class for see how self.canvas is constructed and an extract / description of your layer (geometry type, coordinate system, etc.). – J. Monticolo Jan 29 at 12:53
  • I create a widget in Qt Designer and promote to QgsMapCanvas. Then in dialog in init function I create these lines of code: self.canvas = QgsMapCanvas() self.canvas.setCanvasColor(QColor(255, 255, 255)) self.canvas.setCanvasColor(Qt.white) self.canvas.enableAntiAliasing(True) self.setCentralWidget(self.canvas) And then I define the lines that I put in my original answer. The shapefile is added to the QGIS canvas but not to my QWidget promoted to QgsMapCanvas. The shapefile is a point shapefile in EPSG3763 coordinate system. – Bárbara Duarte Jan 29 at 14:11
  • Thanks for the details. – J. Monticolo Jan 29 at 14:15
2

The problem, I think is that you lost the reference to the QgsVectorLayer outside the function, the solution is to define self.layers, see below :

class My_dlg(QMainWindow):
    def __init__(self, parent=None):
        super(My_dlg, self).__init__(parent)
        self.canvas = QgsMapCanvas()
        self.layers = []
        self.canvas.setCanvasColor(Qt.white)
        self.canvas.enableAntiAliasing(True)
        self.setCentralWidget(self.canvas)
        self.initialize_map()
        self.mt_pan = QgsMapToolPan(self.canvas)
        self.canvas.setMapTool(self.mt_pan)
        print(self.canvas.layerCount())

    def initialize_map(self):
        # display file in canvas
        shpdir = "/"
        fileCI = QFileDialog.getOpenFileName(self, "Open shp", shpdir, "Shapefiles (*.shp)")[0]
        file_info_norm = QFileInfo(str(fileCI))

        # vector layer
        vlayer = QgsVectorLayer(fileCI, "my_layer", "ogr")
        self.layers.append(vlayer)

        if vlayer.isValid():
            self.canvas.setLayers(self.layers)
            self.canvas.waitWhileRendering()
            self.canvas.setExtent(vlayer.extent())
            self.canvas.refresh()
        else:
            print("Layer not valid")


mw = My_dlg()
mw.show()
| improve this answer | |
  • I try exactly as you told me but in this case QGIS crashes again. – Bárbara Duarte Jan 29 at 15:27
  • When I copy this code into my QGIS Python editor and run it, it works perfectly (QGIS 3.10 Ubuntu). – J. Monticolo Jan 29 at 15:52
  • Did you create the QgsMapCanvas in QtDesigner as I did? – Bárbara Duarte Jan 29 at 15:54
  • No, look at the code, it's created at the line 4. – J. Monticolo Jan 29 at 16:03
  • 1
    Try with placing the setupUI just after the line with super(..., and comment / delete the line with self.canvas = QgsMapCanvas() if in Qt Designer, the QgsMapCanvas object name is canvas. – J. Monticolo Jan 29 at 16:43

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.