0

I know, there are several posts about this specific topic (e.g. how to open second window in my plugin for QGIS?), but I am still struggling with some problems.

I have developed a plugin for QGIS 3.34.4 with the PluginBuilder. As one result I got the initial *.ui file and the corresponding *.py file.

I have create a second *.ui file using QTDesigner and converted it via pyuic5 to a *.py file. My problem: I am not able to start the second GUI using a push button in the first GUI.

Here is the *.py file created by the PluginBuilder:

# -*- coding: utf-8 -*-

import os

from qgis.PyQt import uic
from qgis.PyQt import QtWidgets
from PyQt5.QtWidgets import QFileDialog
from qgis.utils import iface

from .secondDialog import Ui_selectionDialog

# 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__), 'ShowSelectedAttribute_dialog_base.ui'))


class ShowSelectedAttributeDialog(QtWidgets.QDialog, FORM_CLASS):
    def __init__(self, parent=None):
        """Constructor."""
        super(ShowSelectedAttributeDialog, 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.setWindowTitle("Mein Plugin-Test")
        self.setupUi(self)
        self.pbSelection.clicked.connect(self.getFeature)
        self.pbExport.clicked.connect(self.exportFeature)
        self.labelOutputSelection.hide()
        self.labelOutputExport.hide()
        self.browsePath.clicked.connect(self.openSecondGUI)


    def getFeature(self):
        pass  

    def exportFeature(self):
        pass

    def openSecondGUI(self):
        secondDialog = Ui_selectionDialog()
        secondDialog.setupUi(secondDialog)

I have already shortened the script here.. The last two lines show one attempt to open the second GUI.

The second *.py file containing the second GUI is this one:

# -*- coding: utf-8 -*-

# Form implementation generated from reading ui file 'C:\Users\Sven Harpering\AppData\Roaming\QGIS\QGIS3\profiles\default\python\plugins\showselectedattribute\secondDialog.ui'
#
# Created by: PyQt5 UI code generator 5.15.4
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again.  Do not edit this file unless you know what you are doing.


from PyQt5 import QtCore, QtGui, QtWidgets


class Ui_selectionDialog(object):
    def setupUi(self, selectionDialog):
        selectionDialog.setObjectName("selectionDialog")
        selectionDialog.resize(400, 300)
        self.buttonBox = QtWidgets.QDialogButtonBox(selectionDialog)
        self.buttonBox.setGeometry(QtCore.QRect(30, 240, 341, 32))
        self.buttonBox.setOrientation(QtCore.Qt.Horizontal)
        self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok)
        self.buttonBox.setObjectName("buttonBox")
        self.pbSelection = QtWidgets.QPushButton(selectionDialog)
        self.pbSelection.setGeometry(QtCore.QRect(30, 50, 271, 51))
        self.pbSelection.setObjectName("pbSelection")
        self.labelOutputSelection_2 = QtWidgets.QLabel(selectionDialog)
        self.labelOutputSelection_2.setGeometry(QtCore.QRect(40, 120, 571, 21))
        self.labelOutputSelection_2.setObjectName("labelOutputSelection_2")

        self.retranslateUi(selectionDialog)
        self.buttonBox.accepted.connect(selectionDialog.accept)
        self.buttonBox.rejected.connect(selectionDialog.reject)
        QtCore.QMetaObject.connectSlotsByName(selectionDialog)

    def retranslateUi(self, selectionDialog):
        _translate = QtCore.QCoreApplication.translate
        selectionDialog.setWindowTitle(_translate("selectionDialog", "Dialog"))
        self.pbSelection.setText(_translate("selectionDialog", "Daten vom selektierten Feature abfragen."))
        self.labelOutputSelection_2.setText(_translate("selectionDialog", "TextLabel"))

I have not changed anything here.

As you can see in the first code snippet, I have already imported the second *.py file via

from .secondDialog import Ui_selectionDialog

Now I'm running out of ideas on how to properly call the setupUI() method so that the second window also appears.

All tutorials that I have found are showing solutions using ".show()" or ".exec_()". However, these are not included after converting the *.ui to a *.py file via pyuic5.

Am I on a wrong path?

1
  • 1
    You mention "several posts about this specific topic" but have not provided links to them.
    – PolyGeo
    Apr 1 at 21:23

1 Answer 1

2

There are of course multiple ways to achieve this. The simplest would be to modify your first dialog .py file like so:

# -*- coding: utf-8 -*-

import os

from qgis.PyQt import uic
from qgis.PyQt import QtWidgets
from PyQt5.QtWidgets import QFileDialog
from qgis.utils import iface

from .secondDialog import Ui_selectionDialog

# 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__), 'ShowSelectedAttribute_dialog_base.ui'))


class ShowSelectedAttributeDialog(QtWidgets.QDialog, FORM_CLASS):
    def __init__(self, parent=None):
        """Constructor."""
        super(ShowSelectedAttributeDialog, 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.setWindowTitle("Mein Plugin-Test")
        self.setupUi(self)
        self.pbSelection.clicked.connect(self.getFeature)
        self.pbExport.clicked.connect(self.exportFeature)
        self.labelOutputSelection.hide()
        self.labelOutputExport.hide()
        self.browsePath.clicked.connect(self.openSecondGUI)


    def getFeature(self):
        pass  

    def exportFeature(self):
        pass

    def openSecondGUI(self):
        # Create an instance of the second dialog class
        second_dlg = SecondDialog(self)
        second_dlg.exec()
        # or second_dlg.show()

# Add this Class definition for your second dialog
class SecondDialog(QtWidgets.QDialog):
    def __init__(self, parent=None):
        super(SecondDialog, self).__init__(parent)
        self.dlg2 = Ui_selectionDialog()
        self.dlg2.setupUi(self)

You can have a look at this tutorial for more details, as it pretty much covers what you are trying to do.

And, yes- you need to use show() or exec(). These are methods inherited by multiple Qt widget classes- the fact that they are not included in the generated .py file is irrelevant. The main difference between them is that exec() starts a new event loop which blocks the rest of the application until the dialog is closed and the loop exits; show() does not.

See: https://stackoverflow.com/questions/35607412/qt-4-8-5-understanding-qmessagebox-exec-and-show

Which you use is up to you depending on your use case.

Finally, the naming of your button browsePath leads me to wonder if you are creating a dialog in order for the user to select a file path or something similar? If that is the case, I would strongly recommend looking at QFileDialog to avoid reinventing the wheel.

1
  • Thank you for your answer and your hin regarding the function browsePath. It was only an example :).
    – kopi
    Apr 3 at 19:03

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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