Qt Quick 控件 - 文本编辑器
使用 Qt Quick 控件的富文本编辑器应用。
《文本编辑示例》允许对 HTML、Markdown 或纯文本文件进行所见即所得编辑。应用程序提供了两个用户界面:一个用于大屏幕,另一个用于小型触控设备。两者都是“纯”QML。《texteditor.cpp》中包含的`main()`函数调用`QFontDatabase::addApplicationFont()`来添加图标字体。(使用 FontLoader 也会是达到相同结果的一种方法。)
桌面用户界面
桌面版本是一个完整的文本编辑器,具有格式化文本以及打开和保存 HTML、Markdown 和纯文本文件的能力。
在模型-视图-控制器(MVC) 设计模式中,控制层包括可以执行的操作集。在 Qt Quick Controls 中,使用Action 类型来封装单个操作或命令。因此,我们首先从一个 Action 对象集开始。
Action { id: openAction shortcut: StandardKey.Open onTriggered: { if (textArea.textDocument.modified) discardDialog.open() else openDialog.open() } }
用于打开文件的 Action 必须首先提示用户如果现有的文档已更改,以避免丢失用户的更改。否则它将简单地打开下面声明的外部FileDialog。
仅当有更改需要保存时,保存文件的 Action 才被启用
Action { id: saveAction shortcut: StandardKey.Save enabled: textArea.textDocument.modified onTriggered: textArea.textDocument.save() }
仅当选择了一些文本时,复制所选文本的 Action 才被启用
Action { id: copyAction shortcut: StandardKey.Copy enabled: textArea.selectedText onTriggered: textArea.copy() }
每个更改文本格式(如加粗、斜体和对齐)的 Action 都是可检查的,其布尔`checked`状态与selected text中的相关属性同步。由于声明性双向同步比较困难,我们使用`onTriggered`脚本来在 Action 被激活时更改属性。`cursorSelection`属性是 Qt 6.7 中的新属性,这使得实现变得容易得多。
Action { id: boldAction shortcut: StandardKey.Bold checkable: true checked: textArea.cursorSelection.font.bold onTriggered: textArea.cursorSelection.font = Qt.font({ bold: checked }) } Action { id: alignCenterAction shortcut: "Ctrl+|" checkable: true checked: textArea.cursorSelection.alignment === Qt.AlignCenter onTriggered: textArea.cursorSelection.alignment = Qt.AlignCenter }
我们有一个包含MenuBar的层次结构和Menus和 MenuItems 的MenuBar。`Platform.MenuItem`没有`action`属性,因此至少需要设置`text`并实现`onTriggered`。
注意:在 Qt Quick Controls 中,每个 MenuItem 可以简单地绑定相应的 action。在 Qt 的未来版本中,Qt.labs.platform
将会过时,MenuBar 将适用于所有平台。除非你需要在 Qt 6.7 及旧版本中使用本地菜单栏(仅在提供该功能的平台上),应避免导入 Qt.labs.platform
。 QtQuick.Controls
更具移植性。
Platform.MenuBar { Platform.Menu { title: qsTr("&File") Platform.MenuItem { text: qsTr("&Open") onTriggered: openAction.trigger() } Platform.MenuItem { text: qsTr("&Save…") onTriggered: saveAction.trigger() } Platform.MenuItem { text: qsTr("Save &As…") onTriggered: saveAsAction.trigger() } Platform.MenuItem { text: qsTr("&Quit") onTriggered: quitAction.trigger() } } Platform.Menu { title: qsTr("&Edit") Platform.MenuItem { text: qsTr("&Copy") enabled: copyAction.enabled onTriggered: copyAction.trigger() } ...
现有的 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 附加属性,以便当文本光标移出视口(例如通过箭头键或输入大量文本时),TextArea 会自动滚动 Flickable 来保持光标可见。
有一个上下文菜单;我们使用一个 TapHandler 来检测右键单击并打开它
TapHandler { acceptedButtons: Qt.RightButton onTapped: contextMenu.open() }
Platform.Menu { id: contextMenu Platform.MenuItem { text: qsTr("Copy") enabled: copyAction.enabled onTriggered: copyAction.trigger() } ...
我们始终使用 qsTr 函数来启用 UI 文本的翻译,以便无论最终用户的母语是什么,应用程序都具有意义。
我们使用多种类型的 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 的两个实例,分别用于打开和保存文件。在 Qt 6.7 中通过在 TextDocument 中引入新功能,这变得更容易。
FontDialog 和 ColorDialog 允许更改文本格式。(在 Markdown 格式中,没有语法来表示特定的字体和颜色选择;但字体特征(如粗体、斜体和等宽)会被保存。在 HTML 格式中,所有格式都会被保存。)
我们有一个 MessageDialog 来显示错误消息,另外两个用于提示用户在文件已被修改时应该做什么。
触摸用户界面
触摸用户界面是文本编辑器的简化版。它适用于屏幕尺寸有限的触摸设备。示例使用 file selectors 来自动加载适当的用户界面。
运行示例
要从 Qt Creator 运行示例,打开 欢迎 模式,并从 示例 中选择示例。更多信息,请访问 构建和运行示例。
© 2024Qt公司有限公司。本文件中包含的文档贡献者的版权。所提供的文档遵循由自由软件基金会发布的GNU自由文档许可协议第1.3版的条款。Qt及其相关标志是芬兰和/或其他国家的The Qt Company Ltd.的商标。商标。所有其他商标均为其各自所有者的财产。