首页 > 解决方案 > 如何从另一个窗口类或额外的 .py 文件(例如 init_events_ui.py)引用和更改 PyQt5 窗口对象

问题描述

是否可以添加另一个 .py 文件(通过导入)并将其用作 PyQt5 Multiwindow 项目其他窗口和主 .py 文件的初始化和事件处理程序?

我有一个包含以下文件的项目: main.py - 导入下面的 Ui...py 文件和 ui_init_events.py 文件的主应用程序

我发现这两个帖子都有帮助,但由于我不知道如何引用 self 对象以外的对象并且找不到解释的地方,所以我被困住了。请参阅:PyQt: 在 PyQt4 中从另一个函数多个窗口修改小部件对象

在第二篇文章中,他们也使用了多窗口(通过 QDialog)对象,但是他们只使用了一个 .py 文件。我正在使用 Visual Studio Code 并构建了 Ui 文件然后编译它们。它们正在进行中,因此我希望进行更多更改,这意味着它们将被覆盖,因此我不想编辑这些文件。

我无法弄清楚如何在另一个窗口中引用和更改属性以进行初始化。线程是:

这是主要部分。目前我使用 self.combobox.additems 调用一个函数来返回一些数据(参见#1),但我认为从 main.py 一遍又一遍地调用它会降低代码的可读性。

(#2) 因此,我想建议如何将现有 PyQt 窗口的所有初始化部分(作为用于生成窗口 + 控件的导入 .py 文件)移动到单独的 .py 文件(例如名为ui_init_events.py)中。然而,在尝试和研究这一点时,我不知道也找不到如何使用它们的完整分层命名约定来引用对象的示例。我已经尝试过应用程序。QWindow.等。我只知道如何使用self。...并且它不起作用(当然,因为这将是指函数本身,我理解它被调用,而不是我想要引用的 PyQt 窗口)。请参阅(#3)什么不起作用。

请对可用于帮助理解 PyQt 如何从对象树的根目录标记其对象的资源提出任何想法,以及如何从 app.py 或其他 .py 文件以外的其他 .py 文件在 Ui_frmConsoleLog 窗口中设置 comboBox_Selector 的示例从 Ui_frmConsoleLog_ui.py 或在 --init--(self, parent=None) 下的类定义中:?

所需的文件结构是这样的:

+-- main.py (or app.py)
      |
      +--- Ui_main_window_ui.py (has setupui & adds objects for main window)
      |
      +--- Ui_main_window_init.py  (has init code for Ui_main_window_ui.py)
      |
      +--- Ui_main_window_events.py  (has event code for Ui_main_window_ui.py)
      |
      +--- Ui_frmConsoleLog_ui.py (has setupui & adds objects for 2nd window)
      |
      +--- Ui_frmConsoleLog_init.py  (has init code for Ui_frmConsoleLog_ui.py)
      |
      +--- Ui_frmConsoleLog_events.py  (has event code for Ui_frmConsoleLog_ui.py)

main.py文件内容

# Default imports
import sys, os, io, sched, time
import ui_resources_rc

from PyQt5.QtCore import QObject, QThread, pyqtSignal
from configparser import ConfigParser
...a portion of code here uses a ini config file for retrieving/saving some settings of the UI & I want to set the properties for each object accordingly...

from PyQt5.QtWidgets import (QApplication, QDialog, QMainWindow, QMessageBox, QWidget)
from PyQt5.uic import loadUi

from Ui_main_window_ui import Ui_MainWindow
from Ui_frmConsoleLog_ui import Ui_frmConsoleLog
from ui_init_events import (funcUpdateFormCombos)

...todo... open a network connection to the system (its an inverter)

# This window will be used for filtering network poll event types
class ConsoleLogWindow(QWidget, Ui_frmConsoleLog):
    def __init__(self):
        super().__init__()
        self.setWindowTitle('Console Log')
        
class AppWindow(QMainWindow, Ui_MainWindow):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.win = None  # No Console Log window visible yet.
        self.setupUi(self)

        #(1) Here is where I will have to call this a lot of times to 
        # populate the vaious window objects which I dont want to do
        self.comboBox_Selector.addItems(funcUpdateFormCombos())

    self.action_Console.triggered.connect(self.OpenConsoleLogWindow)
        self.action_About.triggered.connect(self.about)
        # Populate the controls as per the config file
        #initialise() <-- (2) Here is where I want to call a
        #                 function in ui_init_events.py to setup
        #                 the form's objects as created in QtDesigner
        #                 & exported as a .py file.  I want to continue
        #                 to edit each PyQt window later so I dont want
        #                 to add to the Ui_... files themselves but in
        #                 main.py call a function that has the code to
        #                 set the object fields like checked, combobox
        #                 list contents, etc. 

    def OpenConsoleLogWindow(self, checked):
        if self.win is None:
            self.win = ConsoleLogWindow()
            self.win.show()
        else:
            self.win.close()  # Close window.
            self.win = None  # Discard reference.

if __name__ == "__main__":
    app = QApplication(sys.argv)
    win = AppWindow()
    win.show()
    print('HERE')
    sys.exit(app.exec())

ui_init_events.py文件内容(这是我想在不编辑 PyQt UI 的情况下容纳所有窗口对象设置的文件,将 .ui 转换为 .py 文件,例如我根本不想编辑的 Ui_main_window_u.py 和 Ui_frmConsoleLog_ui.py 。

# Contains the initialisation of widgets fields
def funcUpdateFormCombos():
        LIST = ['Amps', 'Volts', 'Watts']
        LIST.sort()
        return tuple(LIST)

# Would prefer to have a single file per Ui_...py file that houses
# all the events that get triggered for each Ui windows.
# How is this done? eg: <not working> (3)
def initialise()
    frmConsoleLog.self.comboBox_Selector.addItems('Watts','Amps','Volts')

Ui_frmConsoleLog_ui.py的内容(有我要填充的组合框)

from PyQt5 import QtCore, QtGui, QtWidgets

class Ui_frmConsoleLog(object):
    def setupUi(self, frmConsoleLog):
        frmConsoleLog.setObjectName("frmConsoleLog")
        frmConsoleLog.resize(640, 468)
        frmConsoleLog.setToolTip("")
        frmConsoleLog.setStatusTip("")
        frmConsoleLog.setAccessibleName("")
        self.horizontalLayout = QtWidgets.QHBoxLayout(frmConsoleLog)
        self.horizontalLayout.setContentsMargins(0, 1, 0, 0)
        self.horizontalLayout.setObjectName("horizontalLayout")
        self.comboBox_Selector = QtWidgets.QComboBox(frmConsoleLog)
        self.comboBox_Selector.setObjectName("comboBox_Selector")
        self.horizontalLayout.addWidget(self.comboBox_Selector)
        self.textEdit_ConsoleLog = QtWidgets.QTextEdit(frmConsoleLog)
        self.textEdit_ConsoleLog.setEnabled(True)
        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(self.textEdit_ConsoleLog.sizePolicy().hasHeightForWidth())
        self.textEdit_ConsoleLog.setSizePolicy(sizePolicy)
        self.textEdit_ConsoleLog.setObjectName("textEdit_ConsoleLog")
        self.horizontalLayout.addWidget(self.textEdit_ConsoleLog)

        self.retranslateUi(frmConsoleLog)
        QtCore.QMetaObject.connectSlotsByName(frmConsoleLog)

    def retranslateUi(self, frmConsoleLog):
        _translate = QtCore.QCoreApplication.translate
        frmConsoleLog.setWindowTitle(_translate("frmConsoleLog", "Console Log"))

标签: pythonfunctionpyqt5multi-window

解决方案


解决了,感谢我之前帖子中的答案(海报已删除?),这是有效的片段,允许您在另一个.py 文件中的函数在父 main.py 文件中设置 MainWindow pyQt 对象控件属性更整洁的项目。老实说,我不在乎专业开发人员认为这不是好的做法(如果他们这样做,他们的思想就会非常封闭)。

在 app.py (或 main.py - 我有两个文件并且正在使用名称)

class AppWindow(QMainWindow, Ui_MainWindow):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.win = None        # No Console Log window visible yet.
        self.setupUi(self)
        from init_Ui_main_window import (initMainWindow)
        initMainWindow(self)
        ...

在 init_Ui_main_window.py 中:

def initMainWindow(window):
    funcLoadConfig()
    # Populate the controls in the main window
    window.line_Settings_Simple_Default_Selection.setText(str(SETTINGS_SIMPLE_DEFAULT_SELECTOR))

注意: SETTINGS_SIMPLE_DEFAULT_SELECTOR 是一个全局定义的静态变量,在从配置 ini 文件中读取时永远不会更改。如果用户想要覆盖默认值,他们将能够更改行值,但是填充默认值很好。

当initMainWindow(self)从前一个对象上下文中调用self被传递给函数并在函数变量window中设置时那么容易吗,所以要引用主windows对象它只是引用window.[object name as one的一种情况会在 main.py]


推荐阅读