如何使用 qtDesigner 将子窗口停靠在 pyqt5 的 MDI 区域中

How do I dock a subwindow in an MDI Area in pyqt5 using qtDesigner

我正在尝试在 pyqt5 的 MDI 区域中创建一个子 window,为我的主 window 使用 .ui 文件。当我触发显示 subwindow 的操作时,它显示为单独的 window(未按预期停靠在 MDI 区域中)。我已经尝试通过本教程 (codeloop.org MDI Area Tutorial) 添加 subwindow,它工作正常,但我无法通过加载 .ui 文件来复制它。

app.py

import os
import sys
from PyQt5 import QtCore, QtWidgets, uic

scriptPath = os.path.dirname(os.path.realpath(__file__))
uiFile = scriptPath + '\' + 'mainwindow.ui'

class MainWindow(QtWidgets.QMainWindow):
    def __init__(self, *args, **kwargs):
        super(MainWindow, self).__init__(*args, **kwargs)
        self.initUI()
    def initUI(self):
        #load the UI page
        self.ui_main = uic.loadUi(uiFile, self)
        self.action1.triggered.connect(lambda: self.fileBarTrig('test'))
    def fileBarTrig(self,p):
        print(p)
        self.subwindow.show()
        self.mdiArea.tileSubWindows()

def main():
    app = QtWidgets.QApplication(sys.argv)
    main = MainWindow()
    main.show()
    sys.exit(app.exec_())

if __name__ == '__main__':
    main()

mainwindow.ui

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>MainWindow</class>
 <widget class="QMainWindow" name="MainWindow">
  <property name="windowModality">
   <enum>Qt::NonModal</enum>
  </property>
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>800</width>
    <height>600</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>MainWindow</string>
  </property>
  <widget class="QWidget" name="centralwidget">
   <layout class="QVBoxLayout" name="verticalLayout">
    <item alignment="Qt::AlignLeft">
     <widget class="QMdiArea" name="mdiArea">
      <property name="activationOrder">
       <enum>QMdiArea::CreationOrder</enum>
      </property>
      <property name="viewMode">
       <enum>QMdiArea::SubWindowView</enum>
      </property>
      <property name="documentMode">
       <bool>false</bool>
      </property>
      <widget class="QWidget" name="subwindow">
       <property name="windowTitle">
        <string>subwindow</string>
       </property>
       <widget class="QPushButton" name="pushButton">
        <property name="geometry">
         <rect>
          <x>70</x>
          <y>80</y>
          <width>75</width>
          <height>23</height>
         </rect>
        </property>
        <property name="text">
         <string>help</string>
        </property>
       </widget>
      </widget>
      <widget class="QWidget" name="subwindow_2">
       <property name="windowTitle">
        <string>Subwindow</string>
       </property>
      </widget>
     </widget>
    </item>
   </layout>
  </widget>
  <widget class="QMenuBar" name="menubar">
   <property name="geometry">
    <rect>
     <x>0</x>
     <y>0</y>
     <width>800</width>
     <height>21</height>
    </rect>
   </property>
   <widget class="QMenu" name="menuFile">
    <property name="title">
     <string>File</string>
    </property>
    <addaction name="action1"/>
   </widget>
   <addaction name="menuFile"/>
  </widget>
  <widget class="QStatusBar" name="statusbar"/>
  <action name="action1">
   <property name="text">
    <string>1</string>
   </property>
  </action>
 </widget>
 <resources/>
 <connections/>
</ui>

app.py 运行 未停靠子window

QMdiArea中没有插入widget,好像是bug,至少是能力不足,分析一下pyuic5生成的代码就能看出来。

所以解决方案是将小部件添加到 QMdiArea:

import os
import sys
from PyQt5 import QtCore, QtWidgets, uic

scriptPath = os.path.dirname(os.path.realpath(__file__))
uiFile = os.path.join(scriptPath, "mainwindow.ui")


class MainWindow(QtWidgets.QMainWindow):
    def __init__(self, *args, **kwargs):
        super(MainWindow, self).__init__(*args, **kwargs)
        self.initUI()

    def initUI(self):
        # load the UI page
        self.ui_main = uic.loadUi(uiFile, self)
        self.action1.triggered.connect(lambda: self.fileBarTrig("test"))

    def fileBarTrig(self, p):
        sw1 = self.mdiArea.addSubWindow(self.subwindow)
        sw1.show()
        sw2 = self.mdiArea.addSubWindow(self.subwindow_2)
        sw2.show()
        self.mdiArea.tileSubWindows()


def main():
    app = QtWidgets.QApplication(sys.argv)
    main = MainWindow()
    main.show()
    sys.exit(app.exec_())


if __name__ == "__main__":
    main()