如何在 PyQt5 中打开一个新的 MDI sub-window?

How to open a new MDI sub-window in PyQt5?

我想做的是通过单击 Countrypage 本身的“新建”按钮打开一个新的 Countrypage sub-window。

例如,如果我点击 CountryPage window 中的“新建”按钮(window 标题:“国家/地区页面”),则会出现一个新的 Countrypage window 将在 MDI 区域中打开(window 标题:“国家/地区页面 1”)。现在,如果我们单击“国家页面 1”中的“新建”按钮,将在 MDI 区域中打开一个新的 window(window 标题:“国家页面 2”)等等 - 我想一一关闭windows,按Countrypage中相应的“关闭”按钮。新 window 只能通过按“新建”按钮打开。

并且如果我们通过按下“关闭”按钮关闭最后打开的 window,“国家”text-box 中的文本项将自动更新为之前的 window的“国家”text-box 等等。

主脚本:

import sys,os
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *

from sample_countrypage import Countrypage

class MainPage(QMainWindow):
    count = 0

    def __init__(self):
        super().__init__()

        self.mdi = QMdiArea()
        self.mdi.setFixedSize(1000,400)
        self.mdi.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded)
        self.mdi.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)

        self.setWindowTitle(" Sample Programme")
        self.setGeometry(100,100,1600,600)
        self.Ui()
        self.show()

    def Ui(self):
        self.btn1=QPushButton("Country")
        self.btn1.setFixedSize(100, 30)
        self.btn1.clicked.connect(self.countrypage)

        self.left_layout = QVBoxLayout()
        self.right_layout = QHBoxLayout()
        self.main_layout = QHBoxLayout()

        self.left_layout.setContentsMargins(3,5,5,3)
        self.left_layout.addWidget(self.btn1)
        self.left_layout.addStretch()
        self.right_layout.addWidget(self.mdi)

        self.main_layout.setSpacing(5)
        self.main_layout.setContentsMargins(0,0,0,0)
        self.main_layout.addLayout(self.left_layout)
        self.main_layout.addLayout(self.right_layout)
        self.main_layout.addStretch()

        widget = QWidget()
        widget.setLayout(self.main_layout)
        self.setCentralWidget(widget)

        self.subwindow1 = QMdiSubWindow()
        self.subwindow1.setObjectName("SubWindow_1")
        # self.subwindow1.setWindowFlag(Qt.FramelessWindowHint)


    print(Countrypage.btn2click)

    def countrypage(self):
        self.countrywindow = Countrypage()
        self.subwindow1.setWidget(self.countrywindow)
        self.subwindow1.setWindowTitle("Create Country")
        self.subwindow1.setFixedWidth(300)
        self.mdi.addSubWindow(self.subwindow1)
        self.subwindow1.show()
        self.mdi.cascadeSubWindows()
        self.countrywindow.closeRequsted.connect(self.subwindow1close)

    def subwindow1close(self):
        print("close activated from mdi programme")

        self.subwindow1.close()

if __name__ == "__main__":
    app = QApplication(sys.argv)
    mainwindow = MainPage()
    app.setStyle("Windows")
    mainwindow.show()
    sys.exit(app.exec_())

Countrypage.py

import sys,os
from PyQt5.QtWidgets import QWidget,QApplication,QPushButton,QLineEdit,QFormLayout,QVBoxLayout,QHBoxLayout
from PyQt5.QtCore import pyqtSignal

class Countrypage(QWidget):
    closeRequsted = pyqtSignal()
    def __init__(self):
        super().__init__()

        self.btn1 = QPushButton("close")
        self.btn2 = QPushButton("New")
        self.btn1.clicked.connect(self.result)
        self.btn2.clicked.connect(self.btn2click)

        self.tb_country = QLineEdit()
        self.tb_continent =QLineEdit()

        self.form_layout = QFormLayout()
        self.form_layout.addRow("Country",self.tb_country)
        self.form_layout.addRow("continent",self.tb_continent)
        self.form_layout.addRow("",self.btn2)
        self.form_layout.addRow("",self.btn1)
        self.setLayout(self.form_layout)

    def result(self):
        self.closeRequsted.emit()

    def btn2click(self):
        btn2text = (self.btn2.text())
        print(btn2text)

if __name__=="__main__":
    app = QApplication(sys.argv)
    countrywin = Countrypage()
    countrywin.show()
    sys.exit(app.exec_())

sub-windows的添加和关闭最好由main-window处理。 CountryPage class 不需要知道 sub-windows 的任何信息。 new/close 按钮可以直接连接到 main-window 的方法。这使得通过 mdi-area.

的功能更容易管理 sub-windows

下面是您的示例的 re-write,它应该满足您的要求:

主脚本:

import sys, os
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *   

class MainPage(QMainWindow):
    def __init__(self):
        super().__init__()
        self.mdi = QMdiArea()
        self.mdi.setFixedSize(1000, 400)
        self.mdi.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded)
        self.mdi.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
        self.setWindowTitle("Sample Programme")
        self.setGeometry(100, 100, 1600, 600)
        self.Ui()

    def Ui(self):
        self.btn1 = QPushButton("Country")
        self.btn1.setFixedSize(100, 30)
        self.btn1.clicked.connect(self.countrypage)
        self.left_layout = QVBoxLayout()
        self.right_layout = QHBoxLayout()
        self.main_layout = QHBoxLayout()
        self.left_layout.setContentsMargins(3, 5, 5, 3)
        self.left_layout.addWidget(self.btn1)
        self.left_layout.addStretch()
        self.right_layout.addWidget(self.mdi)
        self.main_layout.setSpacing(5)
        self.main_layout.setContentsMargins(0, 0, 0, 0)
        self.main_layout.addLayout(self.left_layout)
        self.main_layout.addLayout(self.right_layout)
        self.main_layout.addStretch()
        widget = QWidget()
        widget.setLayout(self.main_layout)
        self.setCentralWidget(widget)

    def countrypage(self):
        page = Countrypage()
        subwindow = self.mdi.addSubWindow(page)
        subwindow.setWindowTitle("Create Country")
        subwindow.setFixedWidth(300)
        page.btn_close.clicked.connect(self.subwindowclose)
        page.btn_new.clicked.connect(self.countrypage)
        subwindow.show()
        self.mdi.cascadeSubWindows()

    def subwindowclose(self):
        print("close activated from mdi programme")
        current = self.mdi.activeSubWindow()
        if current is not None:
            self.mdi.activatePreviousSubWindow()
            previous = self.mdi.activeSubWindow()
            if previous is not None:
                previous.widget().update_fields(current.widget())
            current.close()

if __name__ == "__main__":

    app = QApplication(sys.argv)
    mainwindow = MainPage()
    app.setStyle("Windows")
    mainwindow.show()
    sys.exit(app.exec_())

Countrypage.py:

import sys,os
from PyQt5.QtWidgets import QWidget,QApplication,QPushButton,QLineEdit,QFormLayout,QVBoxLayout,QHBoxLayout
from PyQt5.QtCore import pyqtSignal

class Countrypage(QWidget):
    def __init__(self):
        super().__init__()
        self.btn_close = QPushButton("Close")
        self.btn_new = QPushButton("New")
        self.tb_country = QLineEdit()
        self.tb_continent = QLineEdit()
        self.form_layout = QFormLayout()
        self.form_layout.addRow("Country", self.tb_country)
        self.form_layout.addRow("Continent", self.tb_continent)
        self.form_layout.addRow("", self.btn_close)
        self.form_layout.addRow("", self.btn_new)
        self.setLayout(self.form_layout)

    def update_fields(self, other):
        if isinstance(other, Countrypage):
            self.tb_country.setText(other.tb_country.text())
            self.tb_continent.setText(other.tb_continent.text())
        else:
            raise TypeError('invalid page type')