コンテンツにスキップ

第 5 章: ダイアログとウィンドウ

多くのアプリケーションでは、メインのウィンドウとは別に、一時的な情報表示や設定変更のためにサブウィンドウ(ダイアログ)が必要になります。 この章では、PySide6 が提供する便利な標準ダイアログと、独自のカスタムダイアログの作成方法について学びます。

ダイアログとは?

ダイアログは、特定のタスクを実行するために一時的に表示されるウィンドウです。 主な特徴として、以下の二つのモードがあります。

  • モーダル (Modal): ダイアログが表示されている間、親ウィンドウの操作がブロックされます。ユーザーに特定の操作(はい/いいえの選択、設定の確定など)を強制したい場合に使用します。dialog.exec()で実行します。
  • モードレス (Modeless): ダイアログが表示されていても、親ウィンドウを操作できます。ワープロの検索ダイアログのように、ダイアログを開いたまま他の作業を続けたい場合に使用します。dialog.show()で実行します。

標準ダイアログの利用

Qt には、よく使われる機能のための標準ダイアログが多数用意されています。 これらを利用することで、開発の手間を省き、OS 標準のルックアンドフィールを提供できます。

QMessageBox: メッセージボックス

ユーザーに情報、警告、エラーを伝えたり、簡単な質問(はい/いいえ/キャンセル)をしたりするためのダイアログです。

from PySide6.QtWidgets import QMessageBox

# 情報ダイアログ
QMessageBox.information(self, "情報", "処理が正常に完了しました。")

# 警告ダイアログ
QMessageBox.warning(self, "警告", "設定が保存されていません。続行しますか?")

# 質問ダイアログ
ret = QMessageBox.question(self, "確認", "本当に削除しますか?",
                         QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No,
                         QMessageBox.StandardButton.No) # デフォルトボタン

if ret == QMessageBox.StandardButton.Yes:
    print("削除処理を実行します。")

QMessageBoxのメソッドはスタティックメソッドなので、インスタンスを作成せずに直接呼び出せるのが特徴です。 第 1 引数のselfは、このダイアログの親ウィンドウを指定します。

QFileDialog: ファイルダイアログ

ファイルのオープンや保存場所をユーザーに選択させるためのダイアログです。

from PySide6.QtWidgets import QFileDialog

# ファイルを開くダイアログ
# 第2引数はキャプション、第3引数はデフォルトディレクトリ
file_path, _ = QFileDialog.getOpenFileName(self, "ファイルを開く", "", "Text Files (*.txt);;All Files (*)")

if file_path:
    print(f"選択されたファイル: {file_path}")
    # ここでファイル読み込み処理などを行う

# ファイルを保存するダイアログ
save_path, _ = QFileDialog.getSaveFileName(self, "名前を付けて保存", "", "Text Files (*.txt)")

if save_path:
    print(f"保存先: {save_path}")
    # ここでファイル書き込み処理などを行う

フィルタ(Text Files (*.txt)の部分)を指定することで、表示されるファイルの種類を制限できます。

カスタムダイアログの作成

設定画面など、より複雑な UI が必要な場合は、QDialogクラスを継承して独自のダイアログを作成します。

QDialogには、accept()(OK が押された)とreject()(キャンセルが押された)という特別なスロットが用意されており、これらをQDialog.Accepted (1) または QDialog.Rejected (0) という結果を返してダイアログを閉じます。

実践:簡単な設定ダイアログ

メインウィンドウから設定ダイアログを開き、そこで選択した値をメインウィンドウに反映させる例を作成します。

custom_dialog_example.py

import sys
from PySide6.QtWidgets import (
    QApplication, QMainWindow, QDialog, QPushButton,
    QVBoxLayout, QDialogButtonBox, QComboBox, QLabel, QWidget
)

# --- カスタムダイアログの定義 ---
class PreferencesDialog(QDialog):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setWindowTitle("設定")

        # ウィジェットの作成
        self.theme_label = QLabel("テーマ:")
        self.theme_combo = QComboBox()
        self.theme_combo.addItems(["Light", "Dark", "Blue"])

        # OK/Cancelボタン (QDialogButtonBoxを使うと便利)
        button_box = QDialogButtonBox(QDialogButtonBox.StandardButton.Ok | QDialogButtonBox.StandardButton.Cancel)
        button_box.accepted.connect(self.accept) # OKボタンのシグナルをacceptスロットに接続
        button_box.rejected.connect(self.reject) # Cancelボタンのシグナルをrejectスロットに接続

        # レイアウト
        layout = QVBoxLayout()
        layout.addWidget(self.theme_label)
        layout.addWidget(self.theme_combo)
        layout.addWidget(button_box)
        self.setLayout(layout)

    def get_selected_theme(self):
        return self.theme_combo.currentText()

# --- メインウィンドウの定義 ---
class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("カスタムダイアログの例")
        self.label = QLabel("現在のテーマ: Light")
        self.button = QPushButton("設定を開く")
        self.button.clicked.connect(self.open_preferences)

        layout = QVBoxLayout()
        layout.addWidget(self.label)
        layout.addWidget(self.button)

        central_widget = QWidget()
        central_widget.setLayout(layout)
        self.setCentralWidget(central_widget)

    def open_preferences(self):
        # ダイアログを作成してモーダルで表示
        dialog = PreferencesDialog(self)

        # exec()はダイアログが閉じられるまでここでブロックする
        result = dialog.exec()

        # OKボタンが押された場合のみ設定を反映
        if result == QDialog.Accepted:
            theme = dialog.get_selected_theme()
            self.label.setText(f"現在のテーマ: {theme}")
            print(f"テーマが'{theme}'に設定されました。")

# --- アプリケーションの実行 ---
if __name__ == "__main__":
    app = QApplication(sys.argv)
    main_win = MainWindow()
    main_win.show()
    sys.exit(app.exec())

この例では、PreferencesDialogが独自のロジック(テーマ選択)と値の取得メソッド(get_selected_theme)を持っています。 メインウィンドウは、ダイアログのexec()QDialog.Acceptedを返したときだけ、その値を取得して UI に反映させています。 これがカスタムダイアログの基本的な使い方です。