PyQGIS Plugin Development – Troubleshooting Multiple Ui Issues

pyqgispythonqgis-plugins

I wrote a plugin in PyQGIS, which contains several Ui's (using QT Designer). When I run the code in the QGIS Python console, it works wonderfully. Now I would like to make it available internally for the company as a classic QGIS plugin (start in menu bar). It always worked well with previous plugins, but there was always only one Ui.

At its core there are three important files. 1. __ init __.py, 2. geowerkzeug.py, which is responsible for starting from the menu, and 3. functionality.py, which contains all my functions.

##__init__.py   
 from Plugin.geowerkzeug import GeoWerkzeug
    
    def classFactory(iface):
        plugin = GeoWerkzeug(iface)
        return plugin

Now the geowerkzeug.py:

from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from plugin.functionality import *
from qgis.utils import iface
import os

class GeoWerkzeug:

    def __init__ (self, iface):
        self.iface = iface

    def initGui (self):
        self.startButton = QAction("Plugin starten", self.iface.mainWindow())    
        self.iface.addPluginToMenu('Plugin', self.startButton)
        self.startButton.triggered.connect(self.maskeAufrufen)

    def unload (self):
        self.iface.removePluginMenu('Plugin', self.startButton)

    def maskeAufrufen (self):
        self.gui = MainWindow(self)
        dock_widget = QDockWidget("Plugin", self.iface.mainWindow())
        dock_widget.setWidget(self.gui)
        self.iface.addDockWidget(QtCore.Qt.RightDockWidgetArea, dock_widget)
        dock_widget.setAllowedAreas(QtCore.Qt.RightDockWidgetArea) 
        self.gui.show()

Up to here it works. MainWindow is the first class on functionality.py. The window will appear. But if I click on a button to switch to the next Ui (class), the Ui does not change. I have a total of 17 Ui's in my plugin. Here I only show two classes as an example.

Now the functionality.py:

from PyQt5.uic import loadUi
from PyQt5 import QtWidgets
from PyQt5.QtWidgets import *
from PyQt5 import *
from qgis.core import *
from qgis.utils import iface
from qgis.gui import *
import processing
from PyQt5 import uic
import os

pluginPath = os.path.dirname(__file__)
uiPath = os.path.join(pluginPath, 'mainwindow.ui')
uiPath_second_window = os.path.join(pluginPath, 'window2.ui')

WIDGET, BASE = uic.loadUiType(uiPath)

widget = QDockWidget()

class MainWindow(BASE, WIDGET):
def __init__(self, parent=None):
        super(MainWindow, self).__init__()
        self.gui = loadUi(uiPath, self)
        self.window_second.clicked.connect(self.next_window)

    def next_window(self):
        window_the_second=Second_window()
        widget.setWidget(window_the_second)

class Second_window(BASE, WIDGET):
    def __init__(self):
        super(Second_window, self).__init__()
        self.gui = loadUi(uiPath_second_window , self)

My biggest problem with understanding is how to correctly link my code from functionality.py (which runs in the console) with the other two files. The next problem is that I don't even get an error message that I could build on.
The plugin is in the menu bar and it can be started, but after that I can't get any further.
I hope my explanations are understandable.

Best Answer

I've tested with a minimal plugin.

This one has two UI files :

  • one mainwindow with one pushbutton nammed pb_one
  • one widget with subwidgets

Here the working code :

#!/usr/bin/env python3

import os

from PyQt5 import uic
from PyQt5.QtWidgets import QAction

pluginPath = os.path.dirname(__file__)
path_ui_one = os.path.join(pluginPath, "ui_one.ui")
path_ui_two = os.path.join(pluginPath, "ui_two.ui")

WIDGET_ONE, BASE_ONE = uic.loadUiType(path_ui_one)
WIDGET_TWO, BASE_TWO = uic.loadUiType(path_ui_two)


def classFactory(iface):
    return TwoUiPlugin(iface)


class TwoUiPlugin:
    def __init__(self, iface):
        self.iface = iface

    def initGui(self):
        self.action = QAction('Test Two UI', self.iface.mainWindow())
        self.action.triggered.connect(self.run)
        self.iface.addToolBarIcon(self.action)

    def unload(self):
        self.iface.removeToolBarIcon(self.action)
        del self.action

    def run(self):
        self.main_widget = MyMainWindow()
        self.main_widget.show()


class MyMainWindow(BASE_ONE, WIDGET_ONE):
    def __init__(self, parent=None):
        super(MyMainWindow, self).__init__()
        self.setupUi(self)
        # change here the method
        # self.pb_one.clicked.connect(self.change_central_widget)
        self.pb_one.clicked.connect(self.display_next_window)
        self.second_widget = SecondWidget()

    def change_central_widget(self):
        self.setCentralWidget(self.second_widget)

    def display_next_window(self):
        self.second_widget.show()


class SecondWidget(BASE_TWO, WIDGET_TWO):
    def __init__(self, parent=None):
        super(SecondWidget, self).__init__()
        self.setupUi(self)
Related Question