简体   繁体   中英

Import Modules in PyQt5

I'm with some problems for adding widgets with PyQt5 to one QMainWindow working with different modules. Basically my GUI has many windows and widgets and i think that would be more organized working with different modules. However, when i try to add a widget from one module to the main module, it gives me an error like the class i'm trying to import is not defined.

To simplify, below you have a very simple test i tried and got the same error of my GUI script. I have two modules, one i called "main_gui_file" and the other is "widget_file".

main_gui_file in this example is the QMainWindow i load in the screen, and i'd like to add a widget in my self.grid_01 calling a function in the module widget_file.

When i run this test, it gives me NameError: name 'Add_Widgets' is not defined

Below you have the both test modules

main_gui_file

from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
import sys

from teste.widget_file import *

class Main_GUI(QMainWindow):

    def __init__(self, *args, **kwargs):

        super(Main_GUI, self).__init__(*args, **kwargs)

        self.setGeometry(0, 0, 500, 500)

        self.main_widget = QStackedWidget()
        self.setCentralWidget(self.main_widget)

        self.widget_01 = QWidget()
        self.main_widget.addWidget(self.widget_01)
        self.grid_01 = QGridLayout()
        self.widget_01.setLayout(self.grid_01)
        self.main_widget.setCurrentWidget(self.widget_01)

        self.label1 = QLabel('a')
        self.label2 = QLabel('b')
        self.grid_01.addWidget(self.label1, 0, 0)
        self.grid_01.addWidget(self.label2, 1, 0)

        self.add_widgets = Add_Widgets()
        self.add_widgets.add_widget()

app = QApplication(sys.argv)
window = Main_GUI()

window.show()
app.exec_()

widget_file

from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *

from teste.main_gui_file import *

class Add_Widgets(QMainWindow):

    def __init__(self, *args, **kwargs):

        super(Add_Widgets, self).__init__(*args, **kwargs)
        self.main_gui = Main_GUI()

    def add_widget(self):

        self.label3 = QLabel('c')
        self.main_gui.grid_01.addWidget(self.label3, 3, 0)

Does anyone know why i'm facing this trouble to import the module? Thanks

The most important problem in your code is that you're doing a circular import (which is usually bad ).

In generic terms, this means that until something "happens", it will not go further with the code.

That's (almost) what is happening:

  • main_gui_file is loaded and at a certain point it tries to import from widget_file
  • widget_file is being imported and tries to load from main_gui_file
  • main_gui_file is processed again, but it tries to go along with it ( simple circular imports are not a real issue, as Python could be able manage them), but at this point widget_file is not going to be completely imported until the main_gui_file has completed
  • the imported main_gui_file from widget_file is now trying to complete the loading
  • the imported main_gui_file also tries to create an instance of Main_GUI , which in turns requires Add_Widgets , which exists in widget_file , but, at that point, it has not been loaded yet, since the import processing is still occupied by trying to complete the loading of main_gui_file
  • Python yells at you because no Add_Widgets exists yet

But that's not enough.

There's a logical problem even on top of that (as @NaufanRusydaFaikar partially explains): you're trying to create a new instance of Main_GUI in the Add_Widgets class, which doesn't make a lot of sense, since one already exists, and that instance is the one you're going to add the widget to.

Also, for the same reason, if you want to add widgets to an existing instance, you really shouldn't create a new QMainWindow, since you're not actually going to use it.

From your code I don't really understand why you need another file to do all that (you might have a good reason, but your code shows none), but I'm going along with it suggesting the following modifications:

main_gui_file.py:

from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
import sys

from widget_file import *

class Main_GUI(QMainWindow):

    def __init__(self, *args, **kwargs):
        # ...
        add_widget()

widget_file.py:

from PyQt5.QtWidgets import *

def add_widget(, layout): # <-- note that there's no "self"
    .label3 = QLabel('c')
    layout.addWidget(, 3, 0)

As you can see, add_widget is now an "orphan" function (by "orphan" I mean that it has no relation besides the module it belongs to, and that can be seen from the fact that it has no indentation and that the first argument is not a self argument it can be related to).
Technically, you could even do the same just by calling add_widget with the layout argument alone and using def add_widget(layout): , but that would prevent you to set the label3 object as an attribute of the main window.

An alternate and better solution (which would also solve the previous logical issue) would be the following:

main_gui_file.py

# ...
class Main_GUI(QMainWindow):
    def __init__(self, *args, **kwargs):
        # ...
        

But only as long as you return the added widget in widget_file.py :

from PyQt5.QtWidgets import *

def add_widget():
    label = QLabel('c')
    layout.addWidget(label, 3, 0)
    

Note that this is not a very elegant way of doing things, as separate imports like these are usually done for "common" functions ("util" functions you usually call for common tasks that don't need an instance argument), and, when dealing with these kind of objects, it's something usually done whenever the imported objects are classes for which instances are going to be created, but that's really a completely different issue.

First, make sure you have file __init__.py in your module directory. Second, from your example, you've tried to import both files which are placed in the same directory. So, try to import the relative path, from teste.widget_file import * would be from.widget_file import * and from teste.main_gui_file import * would be from.main_gui_file import * .


Edit:

To avoid cyclic import, I suggest to change your code to

from PyQt5.QtCore import QObject

class Add_Widgets(QObject):

    def __init__(self, parent, *args, **kwargs):
        super(Add_Widgets, self).__init__(*args, **kwargs)
        self.main_gui = parent

    ...

So you can create Add_Widgets instance by

class Main_GUI(QMainWindow):

    def __init__(self, *args, **kwargs):

        super(Main_GUI, self).__init__(*args, **kwargs)

        ...

        self.add_widgets = Add_Widgets(self)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM