这里我的总体目标是定义一个具有多个重要小部件的主应用程序,其中每个小部件都使用单独的python类定义并从单独的.ui文件加载。
当窗口小部件模块直接加载其.ui文件时,启动主应用程序时似乎无法显示窗口小部件UI。
我希望看到的是这个(图1)
我看到的是这个(图2)
这是生成图2的代码。它摘自最后的HETP_main.py。
QtWidgets.QMainWindow.__init__(self)
Ui_MainWindow.__init__(self)
self.topPanelWDG = TopPanel() # set up behaviors for the top panel
self.setupUi(self)
以下代码将生成图1(我想要的)。但是,它用python代码构造主窗口,而不是从.ui文件加载它。这段代码是使用pyuic5生成的,但是我必须删除注释掉的行才能使其正常工作。
MainWindow.setObjectName("MainWindow")
MainWindow.resize(649, 130)
MainWindow.setStyleSheet("")
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setStyleSheet("QPushButton {background-color: rgb(239, 239, 239)};")
self.centralwidget.setObjectName("centralwidget")
self.verticalLayout = QtWidgets.QVBoxLayout(self.centralwidget)
self.verticalLayout.setObjectName("verticalLayout")
# self.topPanelWDG = QtWidgets.QWidget(self.centralwidget) # removed
# self.topPanelWDG.setMinimumSize(QtCore.QSize(0, 75)) # removed
# self.topPanelWDG.setMaximumSize(QtCore.QSize(16777215, 75)) # removed
# self.topPanelWDG.setStyleSheet("background-color: yellow") # removed
# self.topPanelWDG.setObjectName("topPanelWDG") # removed
self.verticalLayout.addWidget(self.topPanelWDG)
MainWindow.setCentralWidget(self.centralwidget)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
# self.retranslateUi(MainWindow) # removed
# QtCore.QMetaObject.connectSlotsByName(MainWindow) # removed
很明显,我在某种程度上对topPanelWDG进行了双重定义,但是我不知道如何或如何修复它。所以我的问题是,当从.ui文件加载时如何获得图1。
此处附有完整的.py和.ui文件。
以下是.py和两个.ui文件的完整内容。
```from PyQt5 import QtCore, QtGui, QtWidgets, uic
import sys
Ui_MainWindow, QtBaseClass = uic.loadUiType("main.ui")
class TopPanel(QtWidgets.QWidget):
def __init__(self):
super(TopPanel, self).__init__()
uic.loadUi("toppanel.ui", self)
class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self):
QtWidgets.QMainWindow.__init__(self)
Ui_MainWindow.__init__(self)
construct_method = 'load'
construct_method = 'build2'
if construct_method == 'load':
self.topPanelWDG = TopPanel() # set up behaviors for the top panel
self.setupUi(self)
else:
self.topPanelWDG = TopPanel() # set up behaviors for the top panel
self.construct2(self)
self.setWindowTitle(construct_method)
def construct2(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(649, 130)
MainWindow.setStyleSheet("")
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setStyleSheet("QPushButton {background-color: rgb(239, 239, 239)};")
self.centralwidget.setObjectName("centralwidget")
self.verticalLayout = QtWidgets.QVBoxLayout(self.centralwidget)
self.verticalLayout.setObjectName("verticalLayout")
# self.topPanelWDG = QtWidgets.QWidget(self.centralwidget) # removed
# self.topPanelWDG.setMinimumSize(QtCore.QSize(0, 75)) # removed
# self.topPanelWDG.setMaximumSize(QtCore.QSize(16777215, 75)) # removed
# self.topPanelWDG.setStyleSheet("background-color: yellow") # removed
# self.topPanelWDG.setObjectName("topPanelWDG") # removed
self.verticalLayout.addWidget(self.topPanelWDG)
MainWindow.setCentralWidget(self.centralwidget)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
# self.retranslateUi(MainWindow) # removed
# QtCore.QMetaObject.connectSlotsByName(MainWindow) # removed
# def retranslateUi(self, MainWindow): # removed
# _translate = QtCore.QCoreApplication.translate # removed
# MainWindow.setWindowTitle(_translate("MainWindow", "HETP Scanning System")) # removed
app = QtWidgets.QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec_() # should pass command line kwargs?```
```<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Form</class>
<widget class="QWidget" name="Form">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>654</width>
<height>72</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QFrame" name="vanFrame">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>48</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>64</height>
</size>
</property>
<property name="styleSheet">
<string notr="true">
QWidget {background-color: rgb(167, 255, 195)}
.QPushButton {
background-color: LightGray
opacity 0.2;
font: bold;
};</string>
</property>
<property name="frameShape">
<enum>QFrame::Panel</enum>
</property>
<property name="lineWidth">
<number>0</number>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Top Panel</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>```
我很难在问题中包含此内容,因此可以在此处获得。 main.ui
答案 0 :(得分:1)
有两种可能的解决方案。
最简单的方法是从topPanelWDG
中删除main.ui
,然后从代码中手动添加。
from PyQt5 import QtWidgets, uic
# the following line is not necessary, as we can use loadUi in the same way for
# both the widget *and* the main window
# Ui_MainWindow, QtBaseClass = uic.loadUiType("main.ui")
class TopPanel(QtWidgets.QWidget):
def __init__(self):
super(TopPanel, self).__init__()
uic.loadUi("toppanel.ui", self)
class MainWindow(QtWidgets.QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
uic.loadUi("main.ui", self)
self.topPanelWDG = TopPanel()
self.verticalLayout.addWidget(self.topPanelWDG)
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
window = MainWindow()
window.show()
# there's no need to pass args here, usually they're important only to the app
sys.exit(app.exec_())
但是,有时候,您无法轻松地(或不想)将小部件添加到由设计人员根据代码创建的UI的布局中。
一种替代方法是使用Qt所谓的“促销小部件”。
这可以通过向ui中添加小部件来实现,该小部件将用作要实现的实际小部件类的高级“占位符”。在这种特定情况下,它将是标准的QWidget,但是如果您将其他小部件(按钮,表格等)作为子类,则将使用它们,因为它将允许您设置其基本属性(按钮的标签,表的标题等)直接从Designer中获得,而类代码只做您需要实现的事情。
在您的情况下,将topPanelWDG
保留在主ui文件中,右键单击它,然后选择“升级为”。在“升级的类名”中,插入将要使用的类名(TopPanel
),并在“标头文件”字段中输入文件名(包括相对路径,如果有的话)包含TopPanel
类定义(不带py
扩展名)的python文件的子目录中。
最后,单击“添加”,然后单击“升级”,然后保存文件。
这时,您只需要向自定义窗口小部件初始化中添加* args和** kwargs参数。这些是必需的,因为现在创建小部件是Qt的责任,并且由于所有小部件都至少接受一个参数(父级),因此这些参数将在Qt创建它们时添加:如果__init__
函数不接受这些参数参数,则python会引发TypeError
异常,因为它接收到意外的参数。
from PyQt5 import QtWidgets, uic
import sys
class TopPanel(QtWidgets.QWidget):
def __init__(self, *args, **kwargs):
super(TopPanel, self).__init__(*args, **kwargs)
uic.loadUi("toppanel.ui", self)
class MainWindow(QtWidgets.QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
uic.loadUi("main.ui", self)
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
将单独的文件用于自定义窗口小部件通常也是个好习惯,因为每次 都会加载其代码,从而添加了升级的窗口小部件。
这也意味着,如果自定义窗口小部件类位于该文件中,则实际上将运行程序的那部分代码必须包含在if __name__ == "__main__":
语句中;无论如何,这都是一个好习惯,因为无论何时导入文件,它的“主缩进代码”始终会运行。