QML TextArea 入门(二):富文本与换行模式

上一篇讲了 TextArea 的基础输入和字体颜色(见系列第 1 篇),这篇讲内容怎么显示:HTML 富文本的实时渲染,以及三种换行模式的区别。

这篇介绍两个 demo:

  • 富文本 --- 上方纯文本输入,下方富文本实时渲染对比
  • 换行模式 --- 按钮切换 NoWrapWrapWrapAnywhere 三种模式

富文本

这个 demo 用两个 TextArea 上下对比:上方用 PlainText 输入 HTML 标签原文,下方用 RichText 渲染同样的标签,实时预览效果。

演示代码

qml 复制代码
import QtQuick
import QtQuick.Controls
import QtQuick.Controls.Basic
import QtQuick.Layouts

// 富文本:对比纯文本与富文本两种 textFormat 的渲染效果
FadeInAnimation {
    ColumnLayout {
        anchors.fill: parent
        anchors.margins: 20
        spacing: 10

        TitleSeparator {
            title: "富文本"
            description: "上方为纯文本输入区,下方以 RichText 格式实时渲染 HTML 标签"
        }

        TextArea {
            id: textArea
            Layout.fillWidth: true
            Layout.minimumHeight: 120
            textFormat: TextArea.PlainText
            wrapMode: TextArea.Wrap
            text: "<h1>富文本示例</h1><p>这是<b>加粗</b>文本,这是<i>斜体</i>文本。</p><ul><li>列表项1</li><li>列表项2</li></ul>"

            background: Rectangle {
                color: textArea.enabled ? "white" : "#f5f5f5"
                border.color: textArea.activeFocus ? "#1296FF" : "#c0c0c0"
                border.width: textArea.activeFocus ? 2 : 1
                radius: 4
            }
        }

        TextArea {
            id: richView
            Layout.fillWidth: true
            Layout.fillHeight: true
            textFormat: TextArea.RichText
            wrapMode: TextArea.Wrap
            text: textArea.text
            readOnly: true

            background: Rectangle {
                color: "#fafafa"
                border.color: "#c0c0c0"
                border.width: 1
                radius: 4
            }

            onTextChanged: {
                if (textFormat === TextEdit.RichText) {
                    console.log("当前内容为富文本格式")
                }
            }
        }
    }
}

关键逻辑解析

textFormat 两种取值

  • TextArea.PlainText:把 text 当纯文本处理,HTML 标签原样显示。上方输入框用的就是这个,输入 <b>加粗</b> 显示原文。
  • TextArea.RichText:解析 text 里的 HTML 子集标签并渲染样式。下方只读框用 RichText,把同样的内容渲染成加粗、斜体、列表。

双框联动

核心是 text: textArea.text 这一行------把下方渲染框的 text 绑定到上方输入框。上方输入时下方实时刷新,是个简易的"富文本编辑器预览"模式。

支持的 HTML 子集

Qt 的 RichText 不是完整 HTML,支持的有用标签包括:

  • 标题:<h1><h6>
  • 文本样式:<b> 加粗、<i> 斜体、<u> 下划线、<s> 删除线
  • 段落与换行:<p><br>
  • 列表:<ul><li><ol><li>
  • 颜色:<span style="color:red">
  • 链接:<a href="...">

readOnly + 不同背景区分

下方渲染框加了 readOnly: true,背景用 #fafafa 浅灰和上方白色输入框区分,视觉上明确"这里是预览区不可编辑"。

适用场景

任何需要实时预览的场景:富文本编辑器、Markdown 编辑器预览、HTML 邮件模板编辑。把上方输入框换成 Markdown 解析器,下方用 RichText 渲染解析后的 HTML,就是简易 Markdown 编辑器(见本系列后续篇)。

换行模式

这个 demo 用三个按钮切换 wrapMode 三种模式,配合一个 Label 实时显示当前模式,对比不同模式下的文本断行行为。

演示代码

qml 复制代码
import QtQuick
import QtQuick.Controls
import QtQuick.Controls.Basic
import QtQuick.Layouts

// 换行模式:演示 TextArea.NoWrap / Wrap / WrapAnywhere 三种换行模式
FadeInAnimation {
    ColumnLayout {
        anchors.fill: parent
        anchors.margins: 20
        spacing: 15

        TitleSeparator {
            title: "换行模式"
            description: "通过按钮切换 NoWrap、Wrap、WrapAnywhere 三种换行模式"
        }

        TextArea {
            id: wrapTextArea
            Layout.fillWidth: true
            Layout.fillHeight: true
            text: "TextArea is not scrollable by itself. Especially on screen-size constrained platforms, it is often preferable to make entire application pages scrollable. On such a scrollable page, a non-scrollable TextArea might behave better than nested scrollable controls."
            placeholderText: "选择换行模式..."
            clip: true
            selectByMouse: true

            background: Rectangle {
                color: wrapTextArea.enabled ? "white" : "#f5f5f5"
                border.color: wrapTextArea.activeFocus ? "#1296FF" : "#c0c0c0"
                border.width: wrapTextArea.activeFocus ? 2 : 1
                radius: 4
            }
        }

        RowLayout {
            Layout.alignment: Qt.AlignHCenter
            spacing: 10

            Button {
                text: "不换行"
                onClicked: {
                    wrapTextArea.wrapMode = TextArea.NoWrap
                    // 让 wrapMode 立即生效
                    wrapTextArea.width = wrapTextArea.width - 1
                    wrapTextArea.width = wrapTextArea.width + 1
                }
            }

            Button {
                text: "单词换行"
                onClicked: {
                    wrapTextArea.wrapMode = TextArea.Wrap
                    wrapTextArea.width = wrapTextArea.width - 1
                    wrapTextArea.width = wrapTextArea.width + 1
                }
            }

            Button {
                text: "任意位置换行"
                onClicked: {
                    wrapTextArea.wrapMode = TextArea.WrapAnywhere
                    wrapTextArea.width = wrapTextArea.width - 1
                    wrapTextArea.width = wrapTextArea.width + 1
                }
            }

            Label {
                text: {
                    switch (wrapTextArea.wrapMode) {
                        case TextArea.NoWrap: return "当前模式: 不换行"
                        case TextArea.Wrap: return "当前模式: 单词换行"
                        case TextArea.WrapAnywhere: return "当前模式: 任意位置换行"
                        default: return "当前模式: 未知"
                    }
                }
                color: "#1296FF"
                font.bold: true
            }
        }
    }
}

关键逻辑解析

三种换行模式

wrapMode 决定超长文本怎么断行:

模式 行为 适用场景
NoWrap 不换行,文本横向溢出 代码编辑器、单行密文
Wrap 按单词边界换行,不拆词 段落正文、说明文本
WrapAnywhere 任意位置断行,单词可被拆 紧凑显示、长 URL 防溢出

Wrap 是大多数场景的默认选择,保证英文单词完整可读;WrapAnywhere 适合显示超长无空格文本(比如 URL、哈希值),保证内容不溢出控件。

手动触发布局刷新的 hack

onClicked 里有这两行:

qml 复制代码
wrapTextArea.width = wrapTextArea.width - 1
wrapTextArea.width = wrapTextArea.width + 1

这是 QML 里手动触发重新布局的常见技巧。某些 Qt 版本里直接改 wrapMode 不会立即重算文本布局,需要让宽度先减后加触发 widthChanged 信号,强制 TextArea 重排版。如果改 wrapMode 后发现切换没生效,加上这两行就稳了。

Label 用 switch 显示当前模式

Labeltextswitch 语句匹配 wrapTextArea.wrapMode,把枚举值转成中文显示。这是个声明式绑定------wrapMode 变化时 Label 自动刷新,不用手动 onClicked 更新。

三种换行模式对比

维度 NoWrap Wrap WrapAnywhere
文本断行 不换行 单词边界 任意字符
单词完整性 完整 完整 可能被拆
横向溢出
典型场景 代码、单行 段落、说明 URL、长哈希

Wrap 是默认首选;需要横向滚动看长行用 NoWrap;要塞下超长无空格文本用 WrapAnywhere

运行验证

  1. Qt Creator 打开 qml_textarea/CMakeLists.txt
  2. Ctrl+R 运行
  3. 在左侧导航切换"富文本"、"换行模式"两个 demo
  4. 富文本:上方输入 HTML 标签看下方实时渲染(试改 <b><u> 看下划线)
  5. 换行模式:点三个按钮看文本断行行为变化、看右下角 Label 显示当前模式

扩展复用方向

  • 富文本 demo 扩展成 Markdown 编辑器:用 Markdown 解析库(或自己写正则)把 Markdown 转 HTML,再赋值给 RichText 渲染框
  • 富文本加 onLinkActivated 处理 <a> 链接点击,实现预览区可点链接跳转
  • 换行模式加 Text.WordWrapText.WrapAtWordBoundaryOrAnywhere 对比,理解和 TextArea.Wrap 系列的差异
  • 把换行模式 demo 的 wrapMode 切换封装成带默认值的属性,复用到其他 TextArea

已验证环境

相关推荐
大白同学4215 小时前
初识Qt——创建第一个Qt项目
开发语言·qt
秋田君7 小时前
QT_绘图原理双缓冲机制
服务器·数据库·qt
想要入门的程序猿7 小时前
Qt插件QPluginLoader
开发语言·qt
大白同学4219 小时前
初始Qt——了解Qt背景
开发语言·qt
GoKu~9 小时前
Qt图形渲染相关例子
qt
Quz1 天前
QML TextField 应用:自动关联与表单提交
qt
sycmancia1 天前
Qt——自定义控件温度计
开发语言·qt
艾莉丝努力练剑1 天前
【Qt:问题解决】Qt程序入口点错误修复:MinGW ABI兼容问题
java·服务器·开发语言·qt·文件系统·动静态库
邱邱玩编程2 天前
读取位置 0x0000000000000000 时发生访问冲突 | QT | MFC
c++·qt·visualstudio