简体   繁体   English

在 PyQt5 中导入模块

[英]Import Modules in PyQt5

I'm with some problems for adding widgets with PyQt5 to one QMainWindow working with different modules.我在将带有 PyQt5 的小部件添加到一个使用不同模块的 QMainWindow 时遇到了一些问题。 Basically my GUI has many windows and widgets and i think that would be more organized working with different modules.基本上我的 GUI 有许多 windows 和小部件,我认为使用不同的模块会更有条理。 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.但是,当我尝试将一个小部件从一个模块添加到主模块时,它给了我一个错误,例如我尝试导入的 class 未定义。

To simplify, below you have a very simple test i tried and got the same error of my GUI script.为简化起见,下面您有一个非常简单的测试,我尝试过并得到与我的 GUI 脚本相同的错误。 I have two modules, one i called "main_gui_file" and the other is "widget_file".我有两个模块,一个我称为“main_gui_file”,另一个是“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.此示例中的 main_gui_file 是我在屏幕中加载的 QMainWindow,我想在 self.grid_01 中添加一个小部件,调用模块 widget_file 中的 function。

When i run this test, it gives me NameError: name 'Add_Widgets' is not defined当我运行这个测试时,它给了我 NameError: name 'Add_Widgets' is not defined

Below you have the both test modules下面你有两个测试模块

main_gui_file 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.一般而言,这意味着在“发生”某些事情之前,它不会 go 进一步使用代码。

That's (almost) what is happening:这就是(几乎)正在发生的事情:

  • main_gui_file is loaded and at a certain point it tries to import from widget_file main_gui_file已加载,并在某个时刻尝试从widget_file导入
  • widget_file is being imported and tries to load from main_gui_file正在导入widget_file并尝试从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 main_gui_file main_gui_file处理,widget_file尝试go
  • the imported main_gui_file from widget_file is now trying to complete the loadingwidget_file导入的main_gui_file现在正在尝试完成加载
  • 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导入的main_gui_file还尝试创建 Main_GUI 的实例,这Add_Widgets Main_GUI它存在于widget_file中,但是此时尚未加载它,因为尝试完成加载仍然占用了导入处理main_gui_file
  • Python yells at you because no Add_Widgets exists yet Python 对你大喊大叫,因为尚不存在Add_Widgets

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.甚至还有一个逻辑问题(正如@NaufanRusydaFaikar部分解释的那样):您正在尝试在Add_Widgets class 中创建Main_GUI实例,这没有多大意义,因为一个已经存在,而且instance 是您要添加小部件的那个。

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.此外,出于同样的原因,如果您想将小部件添加到现有实例,您真的不应该创建新的 QMainWindow,因为您实际上不会使用它。

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: 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(self, self.grid_01)

widget_file.py:小部件文件.py:

from PyQt5.QtWidgets import *

def add_widget(parent, layout): # <-- note that there's no "self"
    parent.label3 = QLabel('c')
    layout.addWidget(parent.label3, 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).如您所见, add_widget现在是一个“孤儿” function (“孤儿”是指除了它所属的模块之外它没有任何关系,这可以从它没有缩进第一个参数的事实中看出不是一个可以与之相关的self论证)。
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.从技术上讲,您甚至可以通过仅使用 layout 参数调用add_widget并使用def add_widget(layout):来执行相同的操作,但这会阻止您将label3 object 设置为主要 window 的属性。

An alternate and better solution (which would also solve the previous logical issue) would be the following:另一种更好的解决方案(也可以解决之前的逻辑问题)如下:

main_gui_file.py main_gui_file.py

# ...
class Main_GUI(QMainWindow):
    def __init__(self, *args, **kwargs):
        # ...
        self.label3 = add_widget(self.grid_01)

But only as long as you return the added widget in widget_file.py :但只要您在widget_file.py中返回添加的小部件:

from PyQt5.QtWidgets import *

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

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.请注意,这不是一种非常优雅的做事方式,因为像这样的单独导入通常是为“普通”函数(通常为不需要实例参数的普通任务调用的“util”函数)完成的,并且,当处理这些类型的对象时,通常只要导入的对象是要为其创建实例的类,就会这样做,但这确实是一个完全不同的问题。

First, make sure you have file __init__.py in your module directory.首先,确保您的模块目录中有文件__init__.py 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 * .因此,尝试导入相对路径, from teste.widget_file import *将是from.widget_file import *from teste.main_gui_file import *将是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所以你可以通过创建 Add_Widgets 实例

class Main_GUI(QMainWindow):

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

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

        ...

        self.add_widgets = Add_Widgets(self)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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