このページについて

Qt Quick コントロール - テキストエディタ

Qt Quick コントロールを使用したリッチテキストエディタアプリ。

「テキストエディタ」サンプルでは、HTML、Markdown、またはプレーンテキストファイルのWYSIWYG編集が可能です。 このアプリケーションには、大画面用のユーザーインターフェースと、小型のタッチ操作対応デバイス用の簡略化されたUIの2種類が用意されています。どちらも「純粋な」QMLで実装されています。texteditor.cpp には、QFontDatabase::addApplicationFont()を呼び出してアイコンフォントを追加するmain() 関数が含まれています。(FontLoader も、同じ結果を得るための別の方法となります。)

デスクトップ用ユーザーインターフェース

メニューバー、ツールバー、および書式設定済みの文書コンテンツを備えたテキストエディタ

デスクトップ版は、テキストの書式設定や、HTML、Markdown、プレーンテキストファイルの開く・保存機能を備えた完全なテキストエディタです。

モデル・ビュー・コントローラー(MVC)デザインパターンにおいて、コントロール層には実行可能な一連の操作が含まれます。『Qt Quick Controls』では、Action 型が単一の操作やコマンドをカプセル化するために使用されます。したがって、まず一連のActionオブジェクトから始めます:

    Action {
        id: openAction
        text: qsTr("&Open")
        shortcut: StandardKey.Open
        onTriggered: {
            if (textArea.textDocument.modified)
                discardDialog.open()
            else
                openDialog.open()
        }
    }

ファイルを開くためのAction は、ユーザーの変更内容が失われるのを防ぐため、まず既存のドキュメントに変更があるかどうかをユーザーに確認する必要があります。変更がない場合は、後述して宣言されているFileDialog を単に開くだけです。

ファイルの保存を行うAction は、保存すべき変更がある場合にのみ有効になります:

    Action {
        id: saveAction
        text: qsTr("&Save…")
        shortcut: StandardKey.Save
        enabled: textArea.textDocument.modified
        onTriggered: textArea.textDocument.save()
    }

選択したテキストをコピーするためのAction は、テキストが選択されている場合にのみ有効になります:

    Action {
        id: copyAction
        text: qsTr("&Copy")
        shortcut: StandardKey.Copy
        enabled: textArea.selectedText
        onTriggered: textArea.copy()
    }

テキストの書式設定(太字、斜体、配置など)を変更する各アクションはcheckable であり、そのブール値のchecked 状態は、selected text の関連するプロパティと同期しています。宣言型の双方向同期は難しいため、アクションがアクティブ化された際にプロパティを変更するために、onTriggered スクリプトを使用しています。cursorSelection プロパティはQt 6.7で新たに導入されたもので、これにより以前よりもはるかに簡単に実装できるようになりました。

    Action {
        id: boldAction
        text: qsTr("&Bold")
        shortcut: StandardKey.Bold
        checkable: true
        checked: textArea.cursorSelection.font.bold
        onTriggered: textArea.cursorSelection.font.bold = checked
    }

    Action {
        id: alignCenterAction
        text: qsTr("&Center")
        shortcut: "Ctrl+|"
        checkable: true
        checked: textArea.cursorSelection.alignment === Qt.AlignCenter
        onTriggered: textArea.cursorSelection.alignment = Qt.AlignCenter
    }

Menus およびMenuItemsの階層構造を含むMenuBar を用意しています。各MenuItem は、UIの表現と実装をカプセル化したaction をバインドするだけで済みます。

    menuBar: MenuBar {
        Menu {
            title: qsTr("&File")

            MenuItem {
                action: openAction
            }
            MenuItem {
                action: saveAction
            }
            MenuItem {
                action: saveAsAction
            }
            MenuItem {
                action: quitAction
            }
        }

        Menu {
            title: qsTr("&Edit")

            MenuItem {
                action: copyAction
            }
        ...

同じAction オブジェクトがToolBar でも再利用されていますが、ここでは各Actionのtext プロパティをオーバーライドし、アイコンフォントからテキスト形式のアイコンを選択するようにしています:

    header: ToolBar {
        Flow {
            width: parent.width

            Row {
                id: fileRow
                ToolButton {
                    id: openButton
                    text: "\uF115" // icon-folder-open-empty
                    font.family: "fontello"
                    action: openAction
                    focusPolicy: Qt.TabFocus
                }
                ToolButton {
                    id: saveButton
                    text: "\uE80A" // icon-floppy-disk
                    font.family: "fontello"
                    action: saveAction
                    focusPolicy: Qt.TabFocus
                }
                ToolSeparator {
                    contentItem.visible: fileRow.y === editRow.y
                }
            }

            Row {
                id: editRow
                ToolButton {
                    id: copyButton
                    text: "\uF0C5" // icon-docs
                    font.family: "fontello"
                    focusPolicy: Qt.TabFocus
                    action: copyAction
                }
            ...

テキストエディタの主要部分は、Flickable 内に配置されたTextArea です:

    Flickable {
        id: flickable
        flickableDirection: Flickable.VerticalFlick
        anchors.fill: parent

        ScrollBar.vertical: ScrollBar {}

        TextArea.flickable: TextArea {
            id: textArea
            textFormat: Qt.AutoText
            wrapMode: TextArea.Wrap
            focus: true
            selectByMouse: true
            persistentSelection: true
            ...

ScrollBar は垂直軸にアタッチされています。wrapMode を介してワードラップが有効になっているため、水平方向のScrollBar は必要ありません。

TextArea.flickable の添付プロパティは、テキストカーソルがビューポートの外へ移動した際(例えば、矢印キーの操作や大量のテキスト入力など)、TextArea がFlickable をスクロールしてカーソルが見える状態を維持するために使用されます。

MenuBar およびToolBar で宣言したのと同じアクションを、TextArea によって提供される標準のcontext menu 内の既存の項目に追加します:

                const menu = textArea.ContextMenu.menu
                menu.addItem(menuSeparatorComponent.createObject(menu.contentItem))
                menu.addAction(fontDialogAction)
                menu.addAction(colorDialogAction)

UIテキストの翻訳を可能にするため、一貫してqsTr()関数を使用しています。これにより、エンドユーザーの母国語に関係なく、アプリケーションが適切に機能するようになります。

dialogs にはいくつかの種類を使用しています:

    FileDialog {
        id: openDialog
        fileMode: FileDialog.OpenFile
        selectedNameFilter.index: 1
        nameFilters: ["Text files (*.txt)", "HTML files (*.html *.htm)", "Markdown files (*.md *.markdown)"]
        currentFolder: StandardPaths.writableLocation(StandardPaths.DocumentsLocation)
        onAccepted: {
            textArea.textDocument.modified = false // we asked earlier, if necessary
            textArea.textDocument.source = selectedFile
        }
    }

    FileDialog {
        id: saveDialog
        fileMode: FileDialog.SaveFile
        nameFilters: openDialog.nameFilters
        currentFolder: StandardPaths.writableLocation(StandardPaths.DocumentsLocation)
        onAccepted: textArea.textDocument.saveAs(selectedFile)
    }

    FontDialog {
        id: fontDialog
        onAccepted: textArea.cursorSelection.font = selectedFont
    }

    ColorDialog {
        id: colorDialog
        selectedColor: textArea.cursorSelection.color
        onAccepted: textArea.cursorSelection.color = selectedColor
    }

    MessageDialog {
        title: qsTr("Error")
        id: errorDialog
    }

    MessageDialog {
        id : quitDialog
        title: qsTr("Quit?")
        text: qsTr("The file has been modified. Quit anyway?")
        buttons: MessageDialog.Yes | MessageDialog.No
        onButtonClicked: function (button, role) {
            if (role === MessageDialog.YesRole) {
                textArea.textDocument.modified = false
                Qt.quit()
            }
        }
    }

    MessageDialog {
        id : discardDialog
        title: qsTr("Discard changes?")
        text: qsTr("The file has been modified. Open a new file anyway?")
        buttons: MessageDialog.Yes | MessageDialog.No
        onButtonClicked: function (button, role) {
            if (role === MessageDialog.YesRole)
                openDialog.open()
        }
    }

一般的に、目的ごとに個別のインスタンスを宣言する方が簡単です。当チームでは、ファイルの開く操作と保存操作用に、それぞれ2つのFileDialog インスタンスを用意しています。これは、Qt 6.7のTextDocument に追加された新機能により、より簡単になりました。

FontDialog とColorDialog を使用すると、テキストの書式を変更できます。(Markdown形式では、特定のフォントや色を表す構文はありませんが、太字、斜体、等幅フォントなどのフォント特性は保存されます。HTML形式では、すべての書式が保存されます。)

エラーメッセージを表示するためのMessageDialog が1つあり、ファイルが変更された際にユーザーに操作を促すためのものがさらに2つあります。

タッチユーザーインターフェース

書式設定ツールバーを備えた、タッチデバイス向けのテキストエディタインターフェース

タッチユーザーインターフェースは、テキストエディタの簡略版です。画面サイズが限られているタッチデバイスに適しています。この例では、ファイルセレクタを使用して、適切なユーザーインターフェースを自動的に読み込んでいます。

例の動作

以下の手順でサンプルを実行できます:

code.qt.io のサンプルプロジェクト

© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.