Qt Quick Controls - Text-Editor

Eine Rich-Text-Editor-Anwendung mit Qt Quick Controls.

Das Texteditor-Beispiel ermöglicht die WYSIWYG-Bearbeitung einer HTML-, Markdown- oder reinen Textdatei. Die Anwendung verfügt über zwei Benutzeroberflächen: eine für größere Bildschirme und eine vereinfachte Benutzeroberfläche für kleine Touch-basierte Geräte. Beide sind "reines" QML. texteditor.cpp enthält die Funktion main(), die QFontDatabase::addApplicationFont() aufruft, um eine Symbolschriftart hinzuzufügen. (FontLoader wäre eine Alternative, um das gleiche Ergebnis zu erzielen).

Desktop-Benutzeroberfläche

Die Desktop-Version ist ein vollständiger Texteditor mit Möglichkeiten zur Textformatierung und zum Öffnen und Speichern von HTML-, Markdown- und reinen Textdateien.

Beim Model-View-Control (MVC)-Entwurfsmuster umfasst die Steuerebene eine Reihe von Operationen, die ausgeführt werden können. In Qt Quick Controls wird der Typ Action verwendet, um einen einzelnen Vorgang oder Befehl zu kapseln. Dementsprechend beginnen wir mit einer Reihe von Action-Objekten:

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

Das Action zum Öffnen einer Datei muss den Benutzer zunächst fragen, ob das vorhandene Dokument geändert wurde, um zu vermeiden, dass die Änderungen des Benutzers verloren gehen. Andernfalls öffnet es einfach das FileDialog, das weiter unten erklärt wird.

Die Funktion Action zum Speichern der Datei wird nur aktiviert, wenn es Änderungen zu speichern gibt:

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

Die Action zum Kopieren von markiertem Text wird nur aktiviert, wenn Text markiert ist:

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

Jede Aktion zur Änderung der Textformatierung (z. B. fett, kursiv und Ausrichtung) ist checkable, und ihr boolescher checked Zustand ist mit der entsprechenden Eigenschaft in selected text synchronisiert. Da eine deklarative bidirektionale Synchronisierung schwierig ist, verwenden wir ein onTriggered Skript, um die Eigenschaft zu ändern, wenn die Aktion aktiviert wird. Die cursorSelection Eigenschaft ist neu in Qt 6.7 und macht dies viel einfacher als zuvor.

    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
    }

Wir haben eine MenuBar, die die Hierarchie von Menus und MenuItems enthält. Jedes MenuItem muss lediglich das entsprechende action binden, das die UI-Darstellung und die Implementierung kapselt.

    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
            }
        ...

Dieselben Action -Objekte werden in ToolBar wiederverwendet, aber hier überschreiben wir die text -Eigenschaft jeder Aktion, um ein Textsymbol aus unserer Symbolschriftart auszuwählen:

    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
                }
            ...

Der Hauptteil des Texteditors ist ein TextArea innerhalb eines Flickable:

    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
            ...

Ein ScrollBar ist mit der vertikalen Achse verbunden. Da der Wortumbruch über wrapMode aktiviert ist, benötigen wir keine horizontale ScrollBar.

Die Eigenschaft TextArea.flickable attached wird verwendet, damit, wenn der Textcursor aus dem Ansichtsfenster herausbewegt wird (z. B. über Pfeiltasten oder durch Eingabe von viel Text), TextArea den Flickable scrollt, damit der Cursor sichtbar bleibt.

Es gibt ein Kontextmenü; wir verwenden ein TapHandler, um einen Rechtsklick zu erkennen und es zu öffnen:

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

Das Kontextmenü Menu enthält MenuItems, das dieselben Action Objekte wiederverwendet, die auch die Hauptobjekte MenuBar und ToolBar verwenden. Wie zuvor reicht es aus, action an die wiederverwendbare Aktion zu binden, die die auszuführende Operation darstellt. Wir überschreiben jedoch die text jedes Menüeintrags, um die unterstrichenen Mnemonics im Kontextmenü wegzulassen.

    Menu {
        id: contextMenu

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

Wir verwenden konsequent die Funktion qsTr(), um die Übersetzung von UI-Text zu ermöglichen, damit die Anwendung unabhängig von der Muttersprache des Endbenutzers Sinn macht.

Wir verwenden mehrere Arten von 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()
        }
    }

Im Allgemeinen ist es einfacher, für jeden Zweck separate Instanzen zu deklarieren. Wir haben zwei Instanzen von FileDialog, zum Öffnen bzw. Speichern von Dateien. Dies wurde in Qt 6.7 mit den neuen Funktionen von TextDocument einfacher.

Ein FontDialog und ein ColorDialog ermöglichen die Änderung der Textformatierung. (Im Markdown-Format gibt es keine Syntax, um bestimmte Schriftarten und -farben darzustellen, aber Schriftartenmerkmale wie fett, kursiv und Monospace werden gespeichert. Im HTML-Format werden alle Formatierungen gespeichert.)

Wir haben eine MessageDialog, um Fehlermeldungen anzuzeigen, und zwei weitere, um den Benutzer aufzufordern, was zu tun ist, wenn eine Datei geändert wurde.

Touch-Benutzeroberfläche

Die Touch-Benutzeroberfläche ist eine vereinfachte Version des Texteditors. Sie ist für Touch-Geräte mit begrenzter Bildschirmgröße geeignet. Das Beispiel verwendet Dateiselektoren, um die entsprechende Benutzeroberfläche automatisch zu laden.

Ausführen des Beispiels

Zum Ausführen des Beispiels von Qt Creatorzu starten, öffnen Sie den Modus Welcome und wählen Sie das Beispiel aus Examples. Weitere Informationen finden Sie unter Erstellen und Ausführen eines Beispiels.

Beispielprojekt @ code.qt.io

© 2025 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.