diff options
Diffstat (limited to 'examples')
5 files changed, 172 insertions, 83 deletions
diff --git a/examples/quickcontrols/texteditor/doc/src/qtquickcontrols-texteditor.qdoc b/examples/quickcontrols/texteditor/doc/src/qtquickcontrols-texteditor.qdoc index 4f7a9beb04..1e3144f942 100644 --- a/examples/quickcontrols/texteditor/doc/src/qtquickcontrols-texteditor.qdoc +++ b/examples/quickcontrols/texteditor/doc/src/qtquickcontrols-texteditor.qdoc @@ -7,46 +7,152 @@ \keyword Qt Quick Controls 2 - Text Editor \ingroup qtquickcontrols-examples \examplecategory {Graphics} - \brief A QML app using Qt Quick Controls and a C++ class to - provide a fully-functional rich-text editor application. + \brief A rich-text editor app using Qt Quick Controls. - The \e {Text Editor Example} presents a sample HTML file using the TextArea - control, preserving the HTML formatting. The application comes with two user - interfaces; one for traditional desktop platforms with a mouse pointer, and - another simpler, touch-oriented version. + The \e {Text Editor Example} allows WYSIWYG editing of an HTML, Markdown or + plain text file. The application comes with two user interfaces: one for + larger screens, and a simplified UI for small touch-based devices. Both are + "pure" QML. \c texteditor.cpp contains the \c main() function, which calls + QFontDatabase::addApplicationFont() to add an icon font. (\l FontLoader + would be an alternative way to achieve the same result.) \section1 Desktop User Interface \image qtquickcontrols-texteditor-desktop.jpg The desktop version is a complete text editor with capabilities for formatting - text, and opening and saving HTML and plain text files. It demonstrates the - native-looking dialogs and menus using the \l{Qt Labs Platform} module. These - types are mostly suitable for desktop platforms with support for multiple - top-level windows, a mouse pointer, and moderate screen size. + text, and opening and saving HTML, Markdown and plain text files. - The desktop UI uses FileDialog for opening and saving files: + In the \l {https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller}{model-view-control (MVC)} + design pattern, the \e control layer includes the set of operations that + can be performed. In Qt Quick Controls, the \l Action type is used to + encapsulate a single operation or command. Accordingly, we begin with a + set of Action objects: \quotefromfile texteditor/qml/texteditor.qml - \skipto FileDialog - \printuntil /\bsaveAs\b/ - \printline } + \skipto Action + \printuntil openAction + \printto Action + + The \l Action for opening a file must first prompt the user if the existing + document has been changed, to avoid losing the user's changes. Otherwise + it simply opens the FileDialog which is declared further below. + + The \l Action for saving the file is enabled only if there are changes to save: + + \printuntil saveAction + \printto Action + + \skipto quitAction + \skipuntil } + + The \l Action for copying selected text is enabled only if some text is selected: + + \printuntil copyAction + \printuntil } + + \skipto pasteAction + \skipuntil } + + Each Action to change text formatting (such as bold, italic and alignment) + is \l {Action::}{checkable}, and its boolean \c checked state + is in sync with the relevant property in the + \l {TextEdit::selectedText}{selected text}. + Since declarative bidirectional synchronization is difficult, we use + an \c onTriggered script to change the property when the Action is + activated. The \l {TextEdit::}{cursorSelection} property + is new in Qt 6.7 and makes this much easier than it was. + + \printuntil boldAction + \printto Action + + \skipto alignLeftAction + \skipuntil } + + \printuntil alignCenterAction + \printto Action + + We have a \l {Qt.labs.platform::}{MenuBar} containing the hierarchy of + \l {Qt.labs.platform::Menu}{Menus} and MenuItems. \c Platform.MenuItem does + not have an \c action property, so at minimum we need to set \c text and + implement \c onTriggered. + + \note In Qt Quick Controls, each \l {QtQuick.Controls::}{MenuItem} could + simply bind the relevant \l {AbstractButton::}{action}. In a near-future + version of Qt, \c Qt.labs.platform will be obsolete, and + \l {QtQuick.Controls::}{MenuBar} will be suitable on every platform. + Unless you need a native menu bar (only on platforms that provide one) + in Qt 6.7 and older versions, you should avoid importing \c Qt.labs.platform. + \c QtQuick.Controls is more portable. + + \skipto MenuBar + \printuntil copyAction + \printuntil } + \dots 8 - It uses FontDialog and ColorDialog for choosing fonts and colors: + The existing \l Action objects are reused in the \l ToolBar; but here we + override each Action's \l {AbstractButton::}{text} property to + choose a textual icon from our icon font: - \skipto FontDialog - \printuntil /.*colorDialog$/ - \printuntil /^\s{4}\}$/ + \skipto ToolBar + \printuntil copyButton + \printuntil } + \dots 12 - It also uses \l[QML QtLabsPlatform]{Menu} and - \l[QML QtLabsPlatform]{MenuItem} that provide a context menu to format text - within: + The main part of the text editor is a \l TextArea inside a \l Flickable: - \skipto /\bMenu\b/ - \printuntil /^\s{4}\}$/ + \skipto Flickable + \printuntil persistentSelection + \dots 12 - \note There is also a standard menubar with more options than the - context menu. + A \l ScrollBar is attached to the vertical axis. Since word-wrapping is + enabled via \l {TextEdit::}{wrapMode}, we don't need a horizontal + ScrollBar. + + The \l {TextArea::flickable}{TextArea.flickable} attached property is used + so that when the text cursor is moved out of the viewport (for example via + arrow keys, or by typing a lot of text), \l TextArea scrolls the + \l Flickable to keep the cursor visible. + + There is a context menu; we use a TapHandler to detect a right-click and + open it: + + \skipto TapHandler + \printuntil } + + The context \l {Qt.labs.platform::}{Menu} contains + \l {Qt.labs.platform::MenuItem}{MenuItems}. + + \skipto Menu + \printuntil MenuItem + \printuntil } + \dots 8 + + We consistently use the \l qsTr function to enable translation of UI text, + so that the application will make sense regardless of the end user's native + language. + + We use several kinds of \l {Qt Quick Dialogs QML Types}{dialogs}: + + \quotefromfile texteditor/qml/texteditor.qml + \skipto FileDialog + \printuntil discardDialog + \printuntil } + \printuntil } + + It's generally easier to declare separate instances for each purpose. + We have two instances of \l {QtQuick.Dialogs::}{FileDialog}, for opening + and saving files respectively. This became easier in Qt 6.7, with new + features in \l TextDocument. + + A \l {QtQuick.Dialogs::}{FontDialog} and a \l {QtQuick.Dialogs::ColorDialog}{ColorDialog} + allow changing text formatting. (In Markdown format, there's no syntax to + represent specific font and color choices; but font characteristics such as + bold, italic and monospace are saved. In HTML format, all formatting is + saved.) + + We have a \l {QtQuick.Dialogs::}{MessageDialog} to show error messages, and + two more for prompting the user what to do when a file has been modified. \section1 Touch User Interface @@ -57,14 +163,5 @@ \l{Using File Selectors with Qt Quick Controls}{file selectors} to load the appropriate user interface automatically. - Unlike the desktop version, which uses top-level dialogs, the touch version - uses the QML \l Dialog type, which is not a top-level window. This type of - dialog is fully supported on mobile and embedded platforms that do not support - multiple top-level windows. - - \quotefromfile texteditor/qml/+touch/texteditor.qml - \skipto /\bDialog\b/ - \printuntil /^\s{4}\}$/ - \include examples-run.qdocinc */ diff --git a/examples/quickcontrols/texteditor/example.md b/examples/quickcontrols/texteditor/example.md index e385227e3b..f54edab5ae 100644 --- a/examples/quickcontrols/texteditor/example.md +++ b/examples/quickcontrols/texteditor/example.md @@ -1,10 +1,10 @@ # Markdown in Qt Quick The Text, TextEdit and TextArea items support rich text formatted in HTML. -Since Qt 5.14, they now support two dialects of Markdown as well: -[The CommonMark Specification](https://spec.commonmark.org/0.29/) is the +Since Qt 5.14, they support two dialects of Markdown as well: +[The CommonMark Specification](https://spec.commonmark.org/0.31.2/) is the conservative formal specification, while -[GitHub Flavored Markdown](https://guides.github.com/features/mastering-markdown/#GitHub-flavored-markdown) +[GitHub Flavored Markdown](https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax) adds extra features such as task lists and tables. If you are viewing this document in the Qt Quick Controls Text Editor example, @@ -36,7 +36,7 @@ Block { Block quotes can be nested, and block quotes can include indented code blocks. -In [The CommonMark Specification](https://spec.commonmark.org/0.29/) +In [The CommonMark Specification](https://spec.commonmark.org/0.31.2/) John MacFarlane writes: > What distinguishes Markdown from many other lightweight markup syntaxes, @@ -158,7 +158,7 @@ Some Qt Widgets also support Markdown. [QTextEdit](https://doc.qt.io/qt-6/qtextedit.html) has similar WYSIWYG editing features as TextEdit and TextArea: you can edit the rendered text directly. You can use -[QTextDocument::toMarkdown](https://doc-snapshots.qt.io/qt5-dev/qtextdocument.html#toMarkdown) +[QTextDocument::toMarkdown](https://doc.qt.io/qt-6/qtextdocument.html#toMarkdown) to rewrite the Markdown format, and save it back to a file. If you have the [KDE Kate Editor](https://kate-editor.org/) installed on your diff --git a/examples/quickcontrols/texteditor/qml/texteditor.qml b/examples/quickcontrols/texteditor/qml/texteditor.qml index a33aba6f31..9aee7e1e45 100644 --- a/examples/quickcontrols/texteditor/qml/texteditor.qml +++ b/examples/quickcontrols/texteditor/qml/texteditor.qml @@ -6,7 +6,7 @@ import QtCore import QtQuick.Controls import QtQuick.Window import QtQuick.Dialogs -import Qt.labs.platform as Platform +import Qt.labs.platform as Platform // note: soon to be obsolete // TODO: // - make designer-friendly @@ -57,18 +57,21 @@ ApplicationWindow { Action { id: copyAction shortcut: StandardKey.Copy + enabled: textArea.selectedText onTriggered: textArea.copy() } Action { id: cutAction shortcut: StandardKey.Cut + enabled: textArea.selectedText onTriggered: textArea.cut() } Action { id: pasteAction shortcut: StandardKey.Paste + enabled: textArea.canPaste onTriggered: textArea.paste() } @@ -141,15 +144,19 @@ ApplicationWindow { Platform.MenuItem { text: qsTr("&Open") - onTriggered: openDialog.open() + onTriggered: openAction.trigger() } Platform.MenuItem { - text: qsTr("&Save As...") - onTriggered: saveDialog.open() + text: qsTr("&Save…") + onTriggered: saveAction.trigger() + } + Platform.MenuItem { + text: qsTr("Save &As…") + onTriggered: saveAsAction.trigger() } Platform.MenuItem { text: qsTr("&Quit") - onTriggered: close() + onTriggered: quitAction.trigger() } } @@ -158,18 +165,18 @@ ApplicationWindow { Platform.MenuItem { text: qsTr("&Copy") - enabled: textArea.selectedText - onTriggered: textArea.copy() + enabled: copyAction.enabled + onTriggered: copyAction.trigger() } Platform.MenuItem { text: qsTr("Cu&t") - enabled: textArea.selectedText - onTriggered: textArea.cut() + enabled: cutAction.enabled + onTriggered: cutAction.trigger() } Platform.MenuItem { text: qsTr("&Paste") - enabled: textArea.canPaste - onTriggered: textArea.paste() + enabled: pasteAction.enabled + onTriggered: pasteAction.trigger() } } @@ -325,7 +332,6 @@ ApplicationWindow { text: "\uF0C5" // icon-docs font.family: "fontello" focusPolicy: Qt.TabFocus - enabled: textArea.selectedText action: copyAction } ToolButton { @@ -333,7 +339,6 @@ ApplicationWindow { text: "\uE802" // icon-scissors font.family: "fontello" focusPolicy: Qt.TabFocus - enabled: textArea.selectedText action: cutAction } ToolButton { @@ -341,7 +346,6 @@ ApplicationWindow { text: "\uF0EA" // icon-paste font.family: "fontello" focusPolicy: Qt.TabFocus - enabled: textArea.canPaste action: pasteAction } ToolSeparator { @@ -463,6 +467,8 @@ ApplicationWindow { flickableDirection: Flickable.VerticalFlick anchors.fill: parent + ScrollBar.vertical: ScrollBar {} + TextArea.flickable: TextArea { id: textArea textFormat: Qt.RichText @@ -479,10 +485,9 @@ ApplicationWindow { bottomPadding: 0 background: null - MouseArea { + TapHandler { acceptedButtons: Qt.RightButton - anchors.fill: parent - onClicked: contextMenu.open() + onTapped: contextMenu.open() } onLinkActivated: function (link) { @@ -511,8 +516,6 @@ ApplicationWindow { } } } - - ScrollBar.vertical: ScrollBar {} } Platform.Menu { @@ -520,18 +523,18 @@ ApplicationWindow { Platform.MenuItem { text: qsTr("Copy") - enabled: textArea.selectedText - onTriggered: textArea.copy() + enabled: copyAction.enabled + onTriggered: copyAction.trigger() } Platform.MenuItem { text: qsTr("Cut") - enabled: textArea.selectedText - onTriggered: textArea.cut() + enabled: cutAction.enabled + onTriggered: cutAction.trigger() } Platform.MenuItem { text: qsTr("Paste") - enabled: textArea.canPaste - onTriggered: textArea.paste() + enabled: pasteAction.enabled + onTriggered: pasteAction.trigger() } Platform.MenuSeparator {} diff --git a/examples/quickcontrols/texteditor/texteditor.cpp b/examples/quickcontrols/texteditor/texteditor.cpp index dd4800f7b5..7d2d9d0e09 100644 --- a/examples/quickcontrols/texteditor/texteditor.cpp +++ b/examples/quickcontrols/texteditor/texteditor.cpp @@ -18,7 +18,7 @@ int main(int argc, char *argv[]) QGuiApplication::setOrganizationName("QtProject"); #ifdef QT_WIDGETS_LIB - QApplication app(argc, argv); + QApplication app(argc, argv); // only for Qt.labs.platform components #else QGuiApplication app(argc, argv); #endif diff --git a/examples/quickcontrols/texteditor/texteditor.html b/examples/quickcontrols/texteditor/texteditor.html index 3c59a053c5..f53693ec33 100644 --- a/examples/quickcontrols/texteditor/texteditor.html +++ b/examples/quickcontrols/texteditor/texteditor.html @@ -20,24 +20,13 @@ Qt Quick Controls 2 </h2> <p align="center"> - This example demonstrates a modern rich text editor. The UI uses Qt Labs Platforms to provide native menus and dialogs. + This example demonstrates a modern rich text editor. The UI uses Qt Labs Platform to provide native + <a href="https://doc.qt.io/qt-6/qml-qt-labs-platform-menubar.html">menus</a>, + and <a href="https://doc.qt.io/qt-6/qtquick-dialogs-qmlmodule.html">Qt Quick Dialogs</a> for native dialogs. + <a href="https://doc.qt.io/qt-6/qml-qtquick-controls-textarea.html">TextArea</a>, + <a href="https://doc.qt.io/qt-6/qml-qtquick-textedit.html#cursorSelection-prop">TextSelection</a> and + <a href="https://doc.qt.io/qt-6/qml-qtquick-textedit.html#textDocument-prop">TextDocument</a> + provide text-editing API. </p> - <br /> - <br /> - <br /> - - <p> - Below you'll find a list of the native controls used in this application. - </p> - - <ul> - <li><a href="https://doc.qt.io/qt-6/qml-qt-labs-platform-menu.html">Menu</a> - provides a QML API for native platform menu popups.</li> - <li><a href="https://doc.qt.io/qt-6/qml-qt-labs-platform-menubar.html">MenuBar</a> - provides a QML API for native platform menubars.</li> - <li><a href="https://doc.qt.io/qt-6/qml-qt-labs-platform-menuitem.html">MenuItem</a> - provides a QML API for native platform menu items.</li> - <li><a href="https://doc.qt.io/qt-6/qml-qt-labs-platform-filedialog.html">FileDialog</a> - provides a QML API for native platform file dialogs.</li> - <li><a href="https://doc.qt.io/qt-6/qml-qt-labs-platform-fontdialog.html">FontDialog</a> - provides a QML API for native platform font dialogs.</li> - <li><a href="https://doc.qt.io/qt-6/qml-qt-labs-platform-colordialog.html">ColorDialog</a> - provides a QML API for native platform color dialogs.</li> - <li><a href="https://doc.qt.io/qt-6/qml-qt-labs-platform-messagedialog.html">MessageDialog</a> - provides a QML API for native platform message dialogs.</li> - </ul> </body> </html> |