将小部件从.ui文件加载到由单独的.ui文件定义的窗口中

时间:2019-11-14 06:18:20

标签: python pyqt5

这里我的总体目标是定义一个具有多个重要小部件的主应用程序,其中每个小部件都使用单独的python类定义并从单独的.ui文件加载。

当窗口小部件模块直接加载其.ui文件时,启动主应用程序时似乎无法显示窗口小部件UI。

我希望看到的是这个(图1)

enter image description here

我看到的是这个(图2)

enter image description here

这是生成图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文件的完整内容。

HETP_main.py

```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?```

toppanel.ui

```<?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

我很难在问题中包含此内容,因此可以在此处获得。 main.ui

1 个答案:

答案 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文件的子目录中。

Promoting a widget

最后,单击“添加”,然后单击“升级”,然后保存文件。

这时,您只需要向自定义窗口小部件初始化中添加* 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__":语句中;无论如何,这都是一个好习惯,因为无论何时导入文件,它的“主缩进代码”始终会运行。