问题描述
是否可以添加另一个 .py 文件(通过导入)并将其用作 PyQt5 多窗口项目其他窗口和主 .py 文件的初始化和事件处理程序?
我有一个包含以下文件的项目: main.py - 导入 Ui...py 文件和 ui_init_events.py 文件的主应用程序
- main.py - 主程序
- Ui_main_window_ui.py - 一个经过编译的 Qt UI 来显示主窗口
- Ui_frmConsoleLog_ui.py - 一个经过编译的 Qt UI,用于显示带有 textEdit 和 comboBox 对象的窗口
- ui_init_events.py - 我希望这个文件具有设置每个 windows Ui 对象字段的函数,并包含 Ui windows 对象事件,例如 btn.clicked.connect(self.someotherFunc)
我发现这两篇文章都有帮助,但我被卡住了,因为我不知道如何引用 self 对象以外的对象,也找不到解释的地方。见:PyQt: Modifying Widget Object from another Function Multiple Windows in 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 设置 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)
# 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 文件内容(这是我想容纳所有窗口对象的文件setup 无需编辑 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)
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"))
解决方法
解决了,感谢我上一篇文章中的回答(海报被删除了?),这里的代码片段有效并允许您在 另一个 .py 文件中的函数设置 MainWindow pyQt 对象控件用于更整洁项目的父 main.py 文件中的属性。老实说,我不在乎专业开发人员认为这是不好的做法(如果他们这样做,他们的思想非常封闭)。
在 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 中时,因此引用主窗口对象只是引用 window.[object 的一种情况。在 main.py 中命名]