QGIS Plugin Development – How to Add or Select Layer in QGIS Plugin Like QgsProcessingAlgorithm

developmentguipyqgisqgis-plugins

I want to have this add from the file or select layer in my plugin widget like:

enter image description here

I think it can be done with some combination of QgsFileWidget and QgsMapLayerComboBox yet one just selects a file path into text input while another only selects existing layers.

So How to add or select a layer in QGIS standalone plugin (inside any QDialog) (like they do it in QgsProcessingAlgorithm)?

Best Answer

Processing algorithm dialogs use widget wrappers for different parameters such as QgsProcessingMapLayerComboBox, which is what you are referring to. I don't know of a similar generic out-of-the-box 'map layer/ file selection combination widget' which you can use in standard, non-processing Python plugins. I may be wrong here, but I think you will have to implement your own solution by writing a basic kind of widget wrapper. I present a simple example below, for vector layers, which should give you an idea of how this would work and how you could use this idea in a plugin.

from pathlib import Path

class InputLayerFileWidget(QWidget):
    def __init__(self, parent=None):
        self.parent = parent
        QWidget.__init__(self)
        self.v_layout = QVBoxLayout()
        self.lbl = QLabel('Input layer:')
        self.selection_widget = QWidget()
        self.h_layout = QHBoxLayout()
        self.mlcb = QgsMapLayerComboBox(self.selection_widget)
        self.mlcb.setFilters(QgsMapLayerProxyModel.VectorLayer)
        self.file_selection_button = QPushButton("\u2026", self.selection_widget)
        self.file_selection_button.setMaximumWidth(30)
        self.file_selection_button.setToolTip('Select from file')
        for c in self.selection_widget.children():
            self.h_layout.addWidget(c)
        self.selection_widget.setLayout(self.h_layout)
        self.v_layout.addWidget(self.lbl)
        self.v_layout.addWidget(self.selection_widget)
        self.setLayout(self.v_layout)
        
        self.file_selection_button.clicked.connect(self.getFile)
        
    def getFile(self):
        file_name = QFileDialog.getOpenFileName(None, 'Select file', '', filter='*.shp; *.gpkg; *.tab')
        if file_name:
            self.mlcb.setAdditionalItems([file_name[0]])
            self.mlcb.setCurrentIndex(self.mlcb.model().rowCount()-1)
                
    def currentLayer(self):
        layer = self.mlcb.currentLayer()
        if layer is not None:
            return layer
        else:
            path = self.mlcb.currentText()
            name = Path(path).stem
            layer = QgsVectorLayer(path, name, 'ogr')
            if layer.isValid():
                return layer
        return None

class MainDialog(QDialog):
    def __init__(self):
        QDialog.__init__(self)
        self.layout = QVBoxLayout()
        self.input_layer_widget = InputLayerFileWidget(self)
        self.lbl = QLabel('Layer object info...', self)
        self.btn = QPushButton('Get Input Layer', self)
        self.layout.addWidget(self.input_layer_widget)
        for _widget in self.children():
            self.layout.addWidget(_widget)
        self.setLayout(self.layout)
        self.setGeometry(200, 200, 1000, 250)
        
        self.btn.clicked.connect(self.get_input_layer)
    
    def get_input_layer(self):
        self.lbl.setText(str(self.input_layer_widget.currentLayer()))
        
        
w = MainDialog()
w.show()

Demonstration screencast of resulting functionality:

enter image description here

Related Question