Wizard Notes

Python, JavaScript を使った音楽信号分析の技術録、作曲活動に関する雑記

Python:PyQtで複数の画面/ウィンドウ (Widget) を表示する

元ネタ:

www.pythonguis.com

PyQtを使って実用的なアプリを作ろうとすると、描画や設定などの画面を個別に表示するために複数ウィンドウを実装したいことがあります。

まず、素直に以下のようなコードを実装・実行してみます。

import sys
from PyQt5.QtWidgets import (
    QApplication, QMainWindow, QWidget,
    QPushButton, QLabel, QVBoxLayout, 
)


class AnotherWindow(QWidget):
    def __init__(self):
        super().__init__()
        layout = QVBoxLayout()
        self.label = QLabel("Another Window")
        layout.addWidget(self.label)
        self.setLayout(layout)


class MainWindow(QMainWindow):

    def __init__(self):
        super().__init__()
        self.button = QPushButton("Push for Window")
        self.button.clicked.connect(self.show_new_window)
        self.setCentralWidget(self.button)

    def show_new_window(self, checked):
        w = AnotherWindow()
        w.show()


app = QApplication(sys.argv)
w = MainWindow()
w.show()
app.exec()

AnotherWindowが2つ目の画面です。

このコードを実行しても、以下のGIFのように2つ目の画面AnotherWindowはすぐに消えてしまいます

解決策として、PyQtでは新規Widgetを、親となるWidgetMainWindowのメンバ変数とする必要があります。

具体的には、上記のコードではshow_new_window()を以下のように変更すればOKです。

def show_new_window(self, checked):
        self.w = AnotherWindow()
        self.w.show()

実行すると、以下のように2つのウィンドウが表示されました。

3つ以上の場合も同様であり、3つの場合の例を以下に示します。

import sys
from PyQt5.QtWidgets import (
    QApplication, QMainWindow, QWidget,
    QPushButton, QLabel, QVBoxLayout, 
)


class AnotherWindow2(QWidget):
    def __init__(self):
        super().__init__()
        layout = QVBoxLayout()
        self.label = QLabel("Another Window")
        layout.addWidget(self.label)
        self.setLayout(layout)
        
class AnotherWindow(QWidget):
    def __init__(self):
        super().__init__()
        layout = QVBoxLayout()
        self.button = QPushButton("Push AnotherWindow")
        self.button.clicked.connect(self.show_new_window)
        layout.addWidget(self.button)
        self.setLayout(layout)

    def show_new_window(self, checked):
        self.w = AnotherWindow2()
        self.w.show()

class MainWindow(QMainWindow):

    def __init__(self):
        super().__init__()
        self.button = QPushButton("Push MainWindow")
        self.button.clicked.connect(self.show_new_window)
        self.setCentralWidget(self.button)

    def show_new_window(self, checked):
        self.w = AnotherWindow()
        self.w.show()


app = QApplication(sys.argv)
w = MainWindow()
w.show()
app.exec()

実行例: