Qt Quick Controls - テキストエディタ

Qt Quick Controls を使用したリッチテキストエディタ アプリです。

Text Editor Exampleでは、HTML、Markdown、またはプレーンテキストファイルを WYSIWYG で編集できます。このアプリケーションには2つのユーザーインターフェイスがあります:1つは大きなスクリーン用、もう1つは小さなタッチベースのデバイス用の簡素化されたUIです。どちらも "純粋な "QMLです。texteditor.cpp にはmain() 関数が含まれており、QFontDatabase::addApplicationFont() を呼び出してアイコンフォントを追加します。(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 = Qt.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 {
        leftPadding: 8

        Flow {
            id: 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 のアタッチド・プロパティは、テキスト・カーソルが(矢印キーや大量のテキスト入力などで)ビューポートの外に移動すると、TextAreaFlickable をスクロールしてカーソルを表示し続けるために使用されます。

コンテキストメニューがあります。TapHandler を使って右クリックを検出し、それを開きます:

            TapHandler {
                acceptedButtons: Qt.RightButton
                onTapped: contextMenu.popup()
            }

コンテキストMenu には、メインのMenuBarToolBar が使っているのと同じAction オブジェクトを再利用するMenuItems が含まれています。以前と同じように、action を、実行する操作を表す再利用可能なアクションにバインドするだけで十分です。ただし、各メニュー項目のtext をオーバーライドして、コンテキスト・メニューの下線のニーモニックを省略する。

    Menu {
        id: contextMenu

        MenuItem {
            text: qsTr("Copy")
            action: copyAction
        }
        ...

エンドユーザーの母国語に関係なくアプリケーションが理解できるように、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: "black"
        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()
        }
    }

一般的に、それぞれの目的のために別々のインスタンスを宣言する方が簡単です。私たちはFileDialog の2つのインスタンスを持っています。Qt 6.7 では、TextDocument の新機能により、より簡単になりました。

FontDialogColorDialog はテキストのフォーマットを変更することができます。(Markdownフォーマットでは、特定のフォントや色の選択を表す構文はありませんが、太字、斜体、等幅などのフォントの特性は保存されます。HTMLフォーマットでは、すべてのフォーマットが保存されます)。

エラーメッセージを表示するためのMessageDialog 、ファイルが変更されたときにユーザーに何をすべきかを促すための2つのプロンプトがあります。

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

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

例の実行

Qt Creator からサンプルを実行するには、Welcome モードを開き、Examples からサンプルを選択します。詳細については、Building and Running an Example を参照してください。

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

©2024 The Qt Company Ltd. 本書に含まれるドキュメントの著作権は、それぞれの所有者に帰属します。 ここで提供されるドキュメントは、Free Software Foundation が発行したGNU Free Documentation License version 1.3に基づいてライセンスされています。 Qtおよびそれぞれのロゴは、フィンランドおよびその他の国におけるThe Qt Company Ltd.の 商標です。その他すべての商標は、それぞれの所有者に帰属します。