Home > Software engineering >  How to open a new MDI sub-window in PyQt5?
How to open a new MDI sub-window in PyQt5?

Time:02-15

What I want to do is to open a new Countrypage sub-window by clicking on the "New" button which is in Countrypage itself.

For example, if I click the "New" button in a CountryPage window (window title: "Country page"), one more new Countrypage window will be opened in the MDI area (window title: "Country Page 1"). Now if we click the "New" button in "Country Page 1", one more new window will open in the MDI area (window title: "Country page 2") and so on - and I want to close the windows one by one by pressing the corresponding "Close" button in Countrypage. New window are opened only by pressing a "New" button.

And if we close the last opened window by pressing the "Close" button, the text item in the "Country" text-box will be automatically updated in the previous window's "Country" text-box and so on.

Main Script :

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_())

CodePudding user response:

The adding and closing of sub-windows is best handled by the main-window. The CountryPage class doesn't need to know anything about the sub-windows. The new/close buttons can be directly connected to methods of the main-window. This makes it easier to manage the sub-windows via the functions of the mdi-area.

Below is a re-write of your example which should do what you asked for:

Main Script:

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')
  • Related