0

As a PyQt application grows the mainwindow class becomes very crowded, and it is convenient to split the application into modules. In some cases distinctions as to what can be placed into a module are clear, for example a config file that is loaded into the mainwindow class, or a set of methods that take numerical inputs and give numerical outputs. However I am not sure about the murkey area in between, such as when computations are performed on varialbles and these used to generate/update widgets e.g. the toy example below where some computation is performed on mainwindow/config variables, and these are used to generate/update a widget (in my project these are more likely to be plot objects).

This works fine as is, but as my mainwindow class has grown I have begun to place functions such as 'plot_computation' in modules related to the job they perform. Having defined the function in a seperate module there are two options, to pass each individual variable needed to the method, or pass a reference to the entire mainwindow i.e. 'module.plot_computation(self)'. I have taken to the latter as it is feels neater when there are many arguments (4-5).

I was wondering how others structure their applications at the high-level, and what best practices are and if the approach I have taken is reasonable or could be optimised.

from PyQt5 import QtWidgets, QtGui

class UiMainWindow(QtWidgets.QMainWindow):
    def __init__(self):
        super(UiMainWindow, self).__init__()

        # init variables
        self.x = 1
        self.y = 2
        self.data = None
        self.lineedit = None

        # set mainwindow + widgets
        self.mainwidget = QtWidgets.QWidget(self)
        self.mainwidget_gridlayout = QtWidgets.QGridLayout(self.mainwidget)
        self.setCentralWidget(QtWidgets.QWidget(self))
        self.centralWidget().setLayout(self.mainwidget_gridlayout)

        self.button = QtWidgets.QPushButton(self)
        self.mainwidget_gridlayout.addWidget(self.button)
        self.button.pressed.connect(self.plot_computation)

    def plot_computation(self):  # I have begun to move such methods into their own module
        self.data = self.do_computation(self.x, self.y)
        self.lineedit = QtWidgets.QLineEdit(self)
        self.mainwidget_gridlayout.addWidget(self.lineedit)
        self.lineedit.setText(str(self.data))

    def do_computation(self, x, y):  # this method would already be in a seperate module
        result = x + y
        return result


if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    mw = UiMainWindow()
    mw.show()
    sys.exit(app.exec_())
Joseph
  • 578
  • 3
  • 15
  • 1
    This question is actually a very "opinion based" one, and, I've to warn you, those questions are generally closed. Fragmentation/modularization should be done with care, as sometimes they are done unnecessarily. Also, consider that there's absolutely nothing wrong in having a "big" class with lots of methods, and if all of them are actually only being used by the class instances, there's really no benefit in putting them elsewhere: on the contrary, it could make your code unnecessarily "divided", without bringin in any real advantage to the code, the performance or the maintenance. – musicamante Apr 20 '20 at 23:05
  • 1
    Most importantly, if the functions are instance methods, they belong to the class. The only exception would be if you've a method that could be *shared* amongst more classes and that method needs the instance to work with. In that case, create a base class with those methods, and use multiple inheritance. Let's say you've a function that moves the window by some pixels: `def moveBy(self, x, y): self.move(self.x() + x, self.y() + y)`. Create a basic `object` class (for example, `Mover`) implement that method, then create new classes that inherit from it too: `class Window(QWidget, Mover):`. – musicamante Apr 20 '20 at 23:16

0 Answers0