TAGS :Viewed: 18 - Published at: a few seconds ago

[ PyQt Code Splitting - Design Vs Functionality ]

Am struggling to comprehend how to split code in (Py)Qt. The aim is to have the design & navigation tabs in QMainWindow, each tab triggering code in other files. So far it only launches with the ActionClass in the same document / putting in an external document causes 'app not defined' when clicking the tab. The below works without errors, but is clunky.

class Main(QMainWindow):
    def __init__(self):
        QMainWindow.__init__(self)

        self.u = Ui_MainWindow()
        self.u.setupUi(self)

        self.u.tabs.currentChanged.connect(self.TabsChanged)

    def TabsChanged(self, i):
        if i == self.u.tabs.indexOf(self.u.tabFirst): ActionClass.__init__


class ActionClass(Main):
    def __init__(self):
        app.u.lineEdit.setText("test")

app = Main()
app.show()
sys.exit(app.exec_())

The examples I keep seeing have all code in one document. Is there another way to do this e.g. where the ActionClass is in another file/writing u.lineEdit.setText instead of app.u.lineEdit.setText. It seems inheritance & an instance of Main can't be accessed from the ActionClasses doc, so I can't see how they would communicate back to the Main?

Much appreciated

Answer 1


As suggest @M4rtini you can separate your code into python modules. And then import them (use them) in your main module.

For instance the code you posted can be separated in to files:

# actions_class.py

class ActionClass(Main):
    def __init__(self):
        app.u.lineEdit.setText("test")

and

# main.py

from action_class import ActionClass  # This line no need much explanation ;)

class Main(QMainWindow):
    def __init__(self):
        QMainWindow.__init__(self)

        self.u = Ui_MainWindow()
        self.u.setupUi(self)

        self.u.tabs.currentChanged.connect(self.TabsChanged)

    def TabsChanged(self, i):
        if i == self.u.tabs.indexOf(self.u.tabFirst): ActionClass.__init__

app = Main()
app.show()
sys.exit(app.exec_())

In order to understand how import works see the link I left you above.

More explanation

Lest's see:

The correct way of executin code inside a __init__ method is creating an instance. See the example below.

class A:
    def __init__(self):
        print("Executing A.__init__")

print("Doing things wrong")
A.__init__     # This don't print enything
print("Doing things well")
A()            # This works as expected.

So, you line reads:

if i == self.u.tabs.indexOf(self.u.tabFirst): ActionClass.__init__

and should reads:

if i == self.u.tabs.indexOf(self.u.tabFirst): ActionClass()

On the other hand, is a bad practice put code that's not for initialize the instance inside the __init__ methods. If you don't need the instance but yet you want to store the functions inside a class (something like a c++ namespace) you creating use @staticmethod decorator.

class A:

    @staticmethod
    def foo():
        print("Oh, wow, a static method in Python!")

A.foo()

So, your ActionClass could be rewritten as:

class ActionClass(Main):

    @staticmethod
    def do_action:
        app.u.lineEdit.setText("test")

ans then you can use it like this:

 if i == self.u.tabs.indexOf(self.u.tabFirst): ActionClass.do_action()