Qt富文本处理

news2024/12/24 21:01:54

一、富文本文档结构

文本文档由 QTextDocument 类表示,该类包含有关文档内部表示、结构的信息,并跟踪修改以提供撤消/回撤功能。

1.1、基本结构

每个文档始终包含一个根框架,并且始终包含至少一个文本块。

框架/表格总是由文档中的文本块分隔,即使文本块不包含任何信息。这确保了新元素始终可以插入现有结构之间。

1.2、富文档元素

富文本文档通常由文本块(也叫段落)QTextBlock)、框架QTextFrame)、表格QTextTable)、列表QTextList)等常见元素组成。

文档中的基本结构构建元素是 QTextBlock QTextFrameQTextBlock 本身包含富文本片段QTextFragment),但这些片段不会直接影响文档的高级结构。

可以使用 QTextObject 的子类将其他文档元素分组:

  • QTextBlockGroup:将文本块分组。
  • QTextFrame:将框架和其他元素分组。

1.2.1、文本块

文本块将具有不同字符格式的文本片段组合在一起,用于表示文档中的段落。每个块通常包含多个具有不同样式的文本片段

可以通过使用 QTextBlock::iterator 遍历块的内部结构来检查给定块中的片段:

    QTextDocument * docment = ui->textEdit->document();
    QTextBlock block = docment->findBlock(0);    
    for (QTextBlock::iterator it = block.begin(); !(it.atEnd()); ++it)
    {
        QTextFragment currentFragment = it.fragment();
        if (currentFragment.isValid())
        {
            qDebug()<<currentFragment.text();
        }
    }

按顺序遍历文本块:

    QTextBlock currentBlock = docment->begin();
    while (currentBlock.isValid()) 
    {
        //...
        currentBlock = currentBlock.next();
    }

1.2.2、框架

文本框架将文本块和子框架组合在一起,创建大于段落范围的文档结构。

每个框架含至少一个文本块和大于等于零个子框架。

每个文档都有一个包含所有其他文档元素的根框架。因此,除根框架外的所有框架都具有父框架。

可使用 QTextFrame::iterator 遍历框架的子元素:

    QTextDocument * docment = ui->textEdit->document();
    QTextFrame * rootFrame = docment->rootFrame();
    for (QTextFrame::iterator it = rootFrame->begin(); !(it.atEnd()); ++it)
    {
        QTextFrame *childFrame = it.currentFrame();
        QTextBlock childBlock = it.currentBlock();

        if (childFrame)
        {
            //...
        }
        else if (childBlock.isValid())
        {
            //...
        }
    }

1.2.3、表格

表格是按行和列排列的单元格集合。每个单元格都是一个具有字符格式的文档元素,但它也可以包含其他元素,如框架和文本块。

QTextTable QTextFrame 的子类,因此表格在文档结构中被视为框架。

对于文档中遇到的每个框架,可以测试它是否表示一个表格,并以不同的方式处理它: 

    QTextDocument * docment = ui->textEdit->document();
    QTextFrame * rootFrame = docment->rootFrame();
    for (QTextFrame::iterator it = rootFrame->begin(); !(it.atEnd()); ++it)
    {
        QTextFrame *childFrame = it.currentFrame();
        QTextBlock childBlock = it.currentBlock();

        if (childFrame)
        {
            if (QTextTable *childTable = qobject_cast<QTextTable*>(childFrame))
            {
                //...
            }
            else
            {
                //...
            }
        }
        else if (childBlock.isValid())
        {
            //...
        }
    }

可以通过遍历行和列来检查现有表中的单元格。

    for (int row = 0; row < table->rows(); ++row) 
    {
        for (int column = 0; column < table->columns(); ++column) 
        {
            QTextTableCell tableCell = table->cellAt(row, column);
            //...
        }
    }

 1.2.4、列表

列表通常以格式化方式展示文本块序列。

列表可以嵌套和设置缩进。

可以通过列表中的索引来引用每个列表项:

    QTextDocument * docment = ui->textEdit->document();
    QTextBlock block = docment->findBlock(0);   
    if (QTextList * list = block.textList()) 
    {
        for (int index = 0; index < list->count(); ++index) 
        {
            QTextBlock listItem = list->item(index);
            //...
        }
    }

QTextList QTextBlockGroup(可管理文本块分组) 的子类,QTextList 仅为它的列表项提供管理功能,而没有把列表项作为它的子项。 

即在遍历文档时发现的任何文本块实际上都可能是列表项。可以通过以下代码确保正确识别列表项: 

    QTextDocument * docment = ui->textEdit->document();
    QTextFrame * rootFrame = docment->rootFrame();
    for (QTextFrame::iterator it = rootFrame->begin(); !(it.atEnd()); ++it)
    {
        QTextBlock block = it.currentBlock();
        if (block.isValid()) 
        {
            if (QTextList *list = block.textList()) 
            {
                int index = list->itemNumber(block);
                //processListItem(list, index);
            }
        }
    }

二、QTextCursor 接口

2.1、基于光标的文本编辑

QTextCursor 提供了一个基于光标的编辑方式,允许在字符级别操纵 QTextDocument 的内容。

光标会跟踪其在父文档中的位置,并可以报告有关周围结构的信息,例如包围的文本块、框架、表格或列表。

2.1.1、分组光标操作

一系列编辑操作可以打包在一起,以便可以在一个动作中一起回放或撤消。选择包含光标的内容:

    cursor.beginEditBlock();
    cursor.movePosition(QTextCursor::StartOfWord);
    cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor);
    cursor.endEditBlock();

如果编辑操作未分组,文档将自动记录各个操作,以便以后可以撤消这些操作。

2.1.2、多个光标

可以使用多个光标同时编辑同一个文档,尽管用户在编辑小部件中只能看到一个光标。

QTextDocument 确保每个光标正确写入文本,并且不会干扰其他光标。

三、文档布局

文档的布局仅在要在设备上显示时相关。

每个文档的布局都由 QAbstractTextDocumentLayout 类的子类管理。

QTextLayout 用法示例:

#include "widget.h"
#include <QTextLayout>
#include <QPainter>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
{
    auto font = this->font();
    font.setPixelSize(18);
    setFont(font);
}

Widget::~Widget()
{
}

void Widget::paintEvent(QPaintEvent *event)
{
    auto rect = event->rect();
    QTextLayout textLayout("黄河之水天上来,奔流到海不复回", this->font());
    qreal margin = 40;
    qreal radius = qMin(rect.width()/2.0, rect.height()/2.0) - margin;

    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing);
    painter.fillRect(rect, Qt::white);
    painter.setBrush(QBrush(Qt::black));
    painter.setPen(QPen(Qt::black));
    painter.setBrush(QBrush(QColor("#a6ce39")));
    painter.setPen(QPen(Qt::black));
    painter.translate(rect.center());
    painter.drawEllipse(QPointF(0,0),radius,radius);

    painter.setPen(QPen(Qt::red,5));
    for(int i = 0;i < 14;++i)
    {
        auto angle = 25.0 * i;
        auto x = cos(qDegreesToRadians(angle)) * (radius + 20);
        auto y = -sin(qDegreesToRadians(angle)) * (radius + 20);
        painter.drawPoint(x,y);
    }

    textLayout.beginLayout();
    auto angle{0.0f};
    while (true)
    {
        QTextLine line = textLayout.createLine();
        if (!line.isValid())
            break;

        auto x = cos(qDegreesToRadians(angle)) * (radius + 20);
        auto y = -sin(qDegreesToRadians(angle)) * (radius + 20);

        line.setLineWidth(20);
        line.setPosition(QPointF(x,y));
        angle += 25;
    }

    textLayout.endLayout();
    textLayout.draw(&painter, QPoint(0,0));
}

四、常见富文本编辑操作

4.1、使用 QTextEdit

QTextEdit 可以通过以下方式构造并用于显示HTML:

QTextEdit *editor = new QTextEdit(parent);
editor->setHtml(aStringContainingHTMLtext);
editor->show();

默认 QTextEdit 包含一个带有根框架的文档,其中包含一个空文本块。可以获取此文档:

QTextDocument *document = editor->document();

QTextEdit 的光标也可用于编辑文档:

QTextCursor cursor = editor->textCursor();

虽然可以同时使用多个光标编辑文档,但 QTextEdit 一次只显示一个光标。因此,如果想更新编辑器以显示特定的光标或其选择,则需要在修改文档后设置编辑器的光标:

editor->setTextCursor(cursor);

4.2、选择文本

要在文档中的两个点之间选择文本,需要将光标定位在第一个点,然后设置移动模式(QTextCursor::MoveMode)和移动操作(QTextCursor::MoveOperation)移动它。

选择文本时,选择的锚点保留在原来的光标位置:

    cursor.movePosition(QTextCursor::StartOfWord);
    cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor);

4.3、查找文本

QTextDocument 提供了基于光标的搜索功能。

查找文档中所有的特定单词,并更改它们的颜色:

    auto document = ui->textEdit->document();
    auto searchString{"hello"};

    QTextCharFormat colorFormat;
    colorFormat.setBackground(Qt::cyan);
    QTextCursor newCursor(document);
    while (!newCursor.isNull() && !newCursor.atEnd())
    {
        newCursor = document->find(searchString, newCursor);
        if (!newCursor.isNull())
        {
            newCursor.movePosition(QTextCursor::NoMove,QTextCursor::KeepAnchor);
            newCursor.mergeCharFormat(colorFormat);
        }
    }

在每次搜索和替换操作后,不必移动光标,它总是位于搜索和被替换的词的末尾。

五、对HTML的支持

5.1、支持的标记

Qt富文本引擎支持的HTML标记:

a

锚点或链接。更多。

address

地址。更多。

b

加粗。更多。

big比常规的字体大一号的字体。更多。
blockquote

缩进段落。更多。

body文档的主体。更多。
br换行。更多。
center水平居中。更多。
cite表示它所包含的文本是对某个参考文献的引用。更多。
code表示它引用的文本是一段代码,怎么显示交给浏览器。更多。
dd不实用,略。
dfn不实用,略。
div一个块级元素,浏览器通常会在div元素前后放置一个换行符。div标签可以把文档分割为独立的、不同的部分。更多。
dl不实用,略。
dt不实用,略。
em突出显示文本。更多。
font字体,略。
h1~h61~6级的标题。h1是最大的。
head文档头部。更多。
hr显示为一条水平线。更多。
html是 HTML 文档中最外层的元素。更多。
i倾斜文本。更多。
img图片。更多。
kbd不实用,略。
meta提供了 HTML 文档的元数据。元数据不会显示在客户端,但是会被浏览器解析。更多。
li列表项,很实用。更多。
ol有序列表。更多。
ul无序列表。更多。
p

标签定义段落。会自动在标签前后创建一些空白。更多。

pre内容所见即所得。更多。
s删除线。更多。
samp不实用,略。
small小字体。更多。
span

被此元素包含的文本,可以使用独立的样式。更多。

strong粗体突出显示文本。
sub下标文本。更多。
sup上标文本。更多。
tableHTML 表格。更多。
tbody设置表格一部分的样式。更多。
td表格的单元格。更多。
tfoot页脚。更多。
th表头单元格。更多。
thead表头。更多。
title略。
tr表格中的行。更多。
u

文本下划线。

5.2、CSS属性

使用css属性示例:

    ui->textEdit->setHtml(R"(
<head>
        <style>
            body
            {
                text-align:center;
                background-color:green;
            }
            h1
            {
                color:white;
                background-color:blue;
            }
            h2 
            {
                color:white;
                background-color:black;
            }
        </style>
</head>
<body>
        <h1>我是h1</h1>
        <h2>我是h2</h2>
</body>
)");

Qt富文本引擎支持的CSS属性:

background-color背景色。更多。
background-image背景图片。更多。
background所有背景属性。更多。
color文字颜色。更多。

font-family

字体族。更多。
font-style字体样式。更多。
font-weight字体粗细。更多。
font字体所有属性。更多。
text-decoration文本装饰,下划线、上划线、删除线等。更多。
text-indent文本块中首行文本的缩进。更多。
white-space空白的处理方式。更多。

margin-top
margin-bottom
margin-leftpixels
margin-right

元素的四个边距。更多。
padding-top
padding-bottom    
padding-left    
padding-right    
padding
元素填充边距。更多。
vertical-align垂直对齐方式。更多。
border-collapse表格的边框是被合并为一个单一的边框,还是像在标准的 HTML 中那样分开显示。更多。
border-color    
border-top-color
border-bottom-color    
border-left-color    
border-right-color
边框颜色。更多。
border-style
border-top-style
border-bottom-style
border-left-style
border-right-style
边框样式。更多。
border-width
border-top-width    
border-bottom-width
border-left-width
border-right-width
边框宽度。更多。
border    
border-left
border-right
border-top
border-bottom
所有边框属性。更多。
float

指定一个元素的浮动方式。更多。

text-transform文本大小写。更多。
font-variant

可设置将小写字母替换成缩小过的大写字母。更多1。更多2。

line-height以百分比计数的行高。更多。

5.3、Qt特定的CSS属性

可以使用以下Qt特定属性来设置文本块的样式:

  • -qt-block-indent(数值):按指定的数字空格缩进文本块。

测试发现设置为1会缩进半个制表符的空间。

  • -qt-listindent:按指定的空格数缩进列表项

  • -qt-list-number-prefix
  • -qt-list-number-suffix
  • -qt-paragraph-type
  • -qt-table-type
  • -qt-user-state

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/25769.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

16.PyQt5中的事件系统之事件(QEvent)的传递(分发)和处理

PyQt5中的事件系统之事件(QEvent)的传递(分发)和处理 使用Qt编程&#xff0c;几乎不用考虑事件&#xff0c;因为当产生某种事件时&#xff0c;Qt窗口部件都会发射一个相应的信号&#xff08;即Qt会把事件转换为一个对应的信号&#xff09;&#xff0c;比如按钮被按下时&#x…

Servlet是什么?怎么使用?

前言&#xff1a; 服务器里面资源分为动态资源和静态资源 动态资源&#xff1a;Servlet、Jsp 静态资源&#xff1a;HTML、CSS、JS 一、概念 1.什么是servlet&#xff1f; 本质上是一个接口&#xff0c;提供了规范。是java提供的一门动态的web资源开发技术。 2.servlet体…

【C++】string类超详细解析

参考文献&#xff1a;C标准库官网 前言&#xff1a;在C/C的学习过程当中一定一定要多刷题&#xff0c;牛客网作为国内内容超级丰富的IT题库&#xff0c;尤其是它的C、C&#xff0c;有从入门到大厂真题&#xff0c;而且大部分的考试题目也是从中抽取&#xff0c;还有很多面经&am…

智慧职教解决方案-最新全套文件

智慧职教解决方案-最新全套文件一、建设背景二、建设思路三、建设方案四、获取 - 智慧职教全套最新解决方案合集一、建设背景 职业教育目前存在的问题&#xff1a; 发展理念相对落后国际化程度不高基本制度不健全层次结构不合理基础能力相对薄弱社会吸引力不强行业企业参与不…

20221121将行车记录仪记录的MJPEG格式的AVI片段合并的MKV转换为MP4

20221121将行车记录仪记录的MJPEG格式的AVI片段合并的MKV转换为MP4 2022/11/21 21:51 &#xff08;一&#xff09; 缘起&#xff0c;用行车记录仪录制的爬拉胡线&#xff08;惠州大南山&#xff09;的AVI视频&#xff0c;一个片段5分钟。 使用mkvtoolnix-gui将AVI合并成为MKV视…

垂直定位系统实验平台

系统概述 本系统由控制系统和被控对象两部分组成&#xff0c;可根据课程需要进行双轴机构的轴数增减和循序渐进的运动控制实训。 控制系统部分由水平轴执行机构、人机界面机构、电源机构、驱动元件与控制器等组成。控制方式&#xff1a;人机界面模拟控制。 控制对象部分由水…

如何制作传统节日网站(纯HTML代码)

&#x1f389;精彩专栏推荐 &#x1f4ad;文末获取联系 ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业&#xff1a; 【&#x1f4da;毕设项目精品实战案例 (10…

clean-label backdoor attacks 论文笔记

#论文笔记# 1. 论文信息 论文名称Clean-Label Backdoor Attacks作者Alexander Turner(MIT)会议/出版社ICLR 2019pdf本地pdf 在线pdf代码trojanzoo-clean-label**** Label-Consistent其他这篇文章和 Label-Consistent Backdoor Attacks 基本相同 简介&#xff1a;这篇文章是最…

Java内部类解析

作者&#xff1a;~小明学编程 文章专栏&#xff1a;JavaSE基础 格言&#xff1a;目之所及皆为回忆&#xff0c;心之所想皆为过往 目录 什么是内部类 静态内部类 静态内部类访问外部类的规则 外部类访问静态内部类的规则 实例化静态内部类 非静态内部类 内部类访问外部类…

【网安神器篇】——hydra爆破工具

作者名&#xff1a;Demo不是emo 主页面链接&#xff1a;主页传送门创作初心&#xff1a;舞台再大&#xff0c;你不上台&#xff0c;永远是观众&#xff0c;没人会关心你努不努力&#xff0c;摔的痛不痛&#xff0c;他们只会看你最后站在什么位置&#xff0c;然后羡慕或鄙夷座右…

2.16 这些都是我常用的修图工具【玩赚小红书】

一、美图秀秀 P图、拼图、贴纸文字、抠图、视频剪辑等该有的功能都有&#xff0c;有很多现成的高颜值模板可以直接套用。 软件官网&#xff1a;https://pc.meitu.com/ 支持&#xff1a;windows&#xff0c;linux&#xff0c;苹果&#xff0c;安卓手机&#xff0c;苹果手机 ​…

是js高级啊~

JavaScript高级 1.函数 1.1. this绑定规则优先级 隐式绑定的this 大于 默认的this显式绑定的this 大于 隐式绑定的thisnew绑定this 大于 隐式绑定的thisnew绑定的this 大于 bind绑定的优先级bind绑定的this 大于 apply、call绑定的this 备注&#xff1a; new关键字不可以和…

使用idea工具实现新建java项目并连接mysql数据库

1.新建java项目 如果刚打开idea工具&#xff0c;则选择Create new Project。 在里新建使用File > New > Project 新建package包和class文件 右键src > new > package后输入包名 在刚建的包下右键选择 new > Java class后并输入类名 链接mysql Java 连…

win10系统下使用opencv-dnn部署yolov5模型

文章目录前言一、环境1、硬件2、软件二、YOLO模型三、新建Qt项目1、pro文件2、main函数四、YOLO 类封装1、yolo.h2、yolo.cpp3、classes.txt五、效果前言 最近工作中需要用yolov5训练模型&#xff0c;然后在win10系统下&#xff0c;完成推理部署。本篇主要介绍使用opencv-dnn模…

7判断环的入口结点8输出倒数第k个

7.判断环的入口结点 第一次第二次看感觉都无从下手&#xff0c;还是看了题解&#xff0c;主要思路是&#xff1a; 假设前面无环的结点有a个&#xff0c;环有b个结点&#xff0c;则设置快慢结点之后&#xff0c;fast结点一次走两步&#xff0c;slow结点一次走一步。则相遇时fast…

《第一行代码》核心知识点:活动(Activity)的儿子叫碎片(Fragment)

《第一行代码》核心知识点&#xff1a;活动Activity的儿子叫碎片Fragment前言四、活动(Activity)的儿子叫碎片&#xff08;Fragment&#xff09;4.1 碎片是神马&#xff1f;4.2 碎片的基本使用4.3 向容器中动态添加碎片4.4 活动与碎片之间通信方法4.5 碎片的生命周期4.6 使用限…

重载单目运算符以及重载运算符的注意事项

一、单目运算符的重载 单目运算符可分为两种&#xff1a; 1&#xff09;可以放在前面&#xff0c;也可以放在后面的单目&#xff0c;如&#xff1a; -- 2&#xff09;只能放在前面的运算符&#xff1a;&#xff01; &#xff08;正号&#xff09; -&#xff08;负号&#x…

Python函数详解(四)——Python函数参数使用注意事项

今天继续给大家介绍Python相关知识&#xff0c;本文主要内容是Python函数参数使用注意事项。 在上文Python函数详解&#xff08;三&#xff09;——函数的参数传递进阶中&#xff0c;我们学习了函数参数的进阶内容。今天&#xff0c;我们来学习函数的参数使用注意事项。 一、P…

【微信小程序】使用 Cryptiojs 解密微信绑定手机号码

很抱歉断更了一段时间&#xff0c;因为最近在做一个项目比较忙&#xff0c;正好项目中小程序板块需要解密手机号码来提交给接口&#xff0c;小程序中虽然提供了获取手机号按钮点击事件&#xff1a;bindgetphonenumber&#xff0c;但是该事件的处理函数中只能获取到加密过的手机…

关于如何调节Mahony AHRS算法的参数

文章目录一、Mahony算法的控制系统特征多项式二、Kp, Ki参数调节方法三、其他自适应调参法我在之前的博客AHRS互补滤波&#xff08;Mahony&#xff09;算法及开源代码中曾提及Mahony算法的难点在于如何调节PI参数。 最近看到参考文献[1]&#xff0c;提出了基于无阻尼自由频率设…