6

Following the example of getting the QGIS canvas in a plugin window (as described here), I'm trying to add the QgsLayoutDesignerInterface into a plugin widget.

My goal is to simply display (no edit settings needed) a map layout in a plugin widget as soon as the related map is chosen from a combobox (see image below).

Then the layout (added to the project via the project.layoutManager) can wether be directly exported as a pdf file or opened and edited in the main LayoutDesigner (no help needed for this part since I already implemented it)

enter image description here

I tried to promote the QWidget as a QgsLayoutDesignerInterface class to display my automated layout but I get the following error message TypeError: qgis._gui.QgsLayoutDesignerInterface represents a C++ abstract class and cannot be instantiated

wanderzen
  • 2,130
  • 6
  • 26

1 Answers1

6

Based on this quote from your question:

My goal is to simply display (no edit settings needed) a map layout in a plugin widget as soon as the related map is chosen from a combobox .

My guess is that you don't want the entire layout designer interface embedded in your widget, just the layout and associated items.

Because the QgsLayout class inherits from the QGraphicsScene base class, You can create a QGraphicsView object, and display a layout inside it by calling the setScene() method, and passing a QgsPrintLayoutObject.

Below is a basic example which you can adapt for your plugin (you can also run this in the Python console to test).

class MyDialog(QDialog):
    def __init__(self):
        QDialog.__init__(self)
        self.setGeometry(200, 200, 1500, 800)
        self.hbox = QHBoxLayout(self)
        self.side_panel = QWidget(self)
        self.side_panel.setMinimumWidth(300)
        self.cb = QComboBox(self.side_panel)
        self.layout_names = [l.name() for l in QgsProject.instance().layoutManager().layouts()]
        self.cb.addItems(self.layout_names)
        self.cb.currentTextChanged.connect(self.show_layout)
        self.hbox.addWidget(self.side_panel)
        self.layout = QgsProject.instance().layoutManager().layoutByName(self.cb.currentText()).clone()
        # Create a QGraphicsView
        self.view = QGraphicsView(self)
        self.view.setMinimumSize(800, 800)
        # Call setScene(), passing a QgsPrintLayout object
        self.view.setScene(self.layout)
        # Resize layout inside the viewport (just hardcoded here)
        self.view.scale(3, 3)
        self.hbox.addWidget(self.view)
        self.cb.setCurrentText(self.layout.name())

    def show_layout(self):
        layout_name = self.cb.currentText()
        self.layout = QgsProject.instance().layoutManager().layoutByName(layout_name).clone()
        self.view.setScene(self.layout)


dlg = MyDialog()
dlg.show()

Result:

enter image description here

An example with Qt Designer:

enter image description here

from PyQt5 import uic

Dlg, QtBaseClass = uic.loadUiType('C:\Path\To\layoutsDialog.ui')

class LayoutsDialog(QDialog, Dlg): def init(self, parent=None): QDialog.init(self) Dlg.init(self) self.setupUi(self) self.setGeometry(100, 100, 1400, 900) self.setWindowTitle('Display Layouts')

    self.layout_names = [l.name() for l in QgsProject.instance().layoutManager().layouts()]
    self.layoutCB.addItems(self.layout_names)
    self.print_layout = QgsProject.instance().layoutManager().layoutByName(self.layoutCB.currentText())
    self.layoutView.setScene(self.print_layout)
    self.layoutView.scale(3, 3)
    self.layoutCB.currentTextChanged.connect(self.show_layout)

def show_layout(self):
    self.print_layout = QgsProject.instance().layoutManager().layoutByName(self.layoutCB.currentText())
    self.layoutView.setScene(self.print_layout)


dlg = LayoutsDialog() dlg.show()

enter image description here

Ben W
  • 21,426
  • 3
  • 15
  • 39