PyQt5 のファイルを開くダイアログとテキストエディタ

PyQt5 のファイルを開くダイアログとテキストエディタ

小さなテキストエディタは、PyQt5 の最初のプロジェクトとして適しています。メインウィンドウ、中央ウィジェット、メニュー、アクション、ファイルダイアログといった、Qt でよく使う考え方をいくつも扱うからです。

以下の例では、テキストファイルを開き、QTextEdit に表示し、内容を編集してディスクへ保存し直せるシンプルなエディタを作成します。

import sys

from PyQt5.QtWidgets import (
    QAction,
    QApplication,
    QFileDialog,
    QMainWindow,
    QMessageBox,
    QTextEdit,
)


class TextEditor(QMainWindow):
    def __init__(self):
        super().__init__()

        self.current_file = None
        self.editor = QTextEdit()
        self.setCentralWidget(self.editor)

        self.init_ui()

    def init_ui(self):
        self.setWindowTitle("PyQt5 Text Editor")
        self.resize(800, 600)

        open_action = QAction("Open", self)
        open_action.setShortcut("Ctrl+O")
        open_action.triggered.connect(self.open_file)

        save_action = QAction("Save", self)
        save_action.setShortcut("Ctrl+S")
        save_action.triggered.connect(self.save_file)

        save_as_action = QAction("Save As", self)
        save_as_action.setShortcut("Ctrl+Shift+S")
        save_as_action.triggered.connect(self.save_file_as)

        exit_action = QAction("Exit", self)
        exit_action.setShortcut("Ctrl+Q")
        exit_action.triggered.connect(self.close)

        file_menu = self.menuBar().addMenu("File")
        file_menu.addAction(open_action)
        file_menu.addAction(save_action)
        file_menu.addAction(save_as_action)
        file_menu.addSeparator()
        file_menu.addAction(exit_action)

    def open_file(self):
        file_name, _ = QFileDialog.getOpenFileName(
            self,
            "Open File",
            "",
            "Text Files (*.txt);;Python Files (*.py);;All Files (*)",
        )

        if not file_name:
            return

        try:
            with open(file_name, "r", encoding="utf-8") as file:
                self.editor.setPlainText(file.read())
        except OSError as error:
            QMessageBox.critical(self, "Open Error", str(error))
            return

        self.current_file = file_name
        self.setWindowTitle(f"PyQt5 Text Editor - {file_name}")

    def save_file(self):
        if self.current_file is None:
            self.save_file_as()
            return

        try:
            with open(self.current_file, "w", encoding="utf-8") as file:
                file.write(self.editor.toPlainText())
        except OSError as error:
            QMessageBox.critical(self, "Save Error", str(error))

    def save_file_as(self):
        file_name, _ = QFileDialog.getSaveFileName(
            self,
            "Save File",
            "",
            "Text Files (*.txt);;Python Files (*.py);;All Files (*)",
        )

        if not file_name:
            return

        self.current_file = file_name
        self.save_file()
        self.setWindowTitle(f"PyQt5 Text Editor - {file_name}")


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

仕組み

QMainWindow は、アプリケーションに標準的なウィンドウ構造を提供します。QTextEdit ウィジェットは、setCentralWidget() によってウィンドウ中央に配置されます。

QAction オブジェクトはメニューコマンドを定義します。各アクションは、シグナル・スロット機構を使ってメソッドに接続されます。

open_action.triggered.connect(self.open_file)

ファイルダイアログは、選択されたファイルパスと選択されたフィルターの 2 つの値を返します。この例では、必要なのはパスだけです。

file_name, _ = QFileDialog.getOpenFileName(self, "Open File")

ユーザーがダイアログをキャンセルした場合、file_name は空になるため、関数は何もせずに戻ります。

プログラムの実行

PyQt5 がまだ利用できない場合はインストールします。

pip install PyQt5

スクリプトを text_editor.py として保存し、次のように実行します。

python text_editor.py

これはまだ最小限のエディタです。次の改善としては、未保存の変更に対する警告、行番号、最近使ったファイル、異なるエンコーディングへの対応などを追加するとよいでしょう。

Leave a Reply