Qt中富文本处理相关类

1、QAbstractTextDocumentLayout:抽象基类,用于实现QTextDocuments的自定义布局。Qt提供的标准布局可以处理简单的字处理,包括内联图像、列表和表。有些应用程序,例如文字处理程序或DTP应用程序可能需要比Qt布局引擎提供的功能更多的特性,在这种情况下,您可以子类化QAbstractTextDocumentLayout以为文本文档提供定制布局行为。

2、QFont:指定用于绘制文本的字体。用于设置字体、大小、格式等

3、QSyntaxHighlighter:允许您定义语法高亮显示规则,此外,您还可以使用该类查询文档的当前格式或用户数据

class Highlighter : public QSyntaxHighlighter
{
    Q_OBJECT
public:
    Highlighter(QTextDocument *parent = 0);
protected:
    /*
     * 要提供自己的语法高亮显示,必须子类化QSyntaxHighlighter并重新实现highlightBlock()。
     * 在重新实现时,应该解析块的文本,并根据需要经常调用setFormat()来应用所需的任何字体和颜色更改。
     */
    void highlightBlock(const QString &text) override;

private:
    struct HighlightingRule
    {
        QRegularExpression pattern;
        QTextCharFormat format;
    };
    QVector<HighlightingRule> highlightingRules;//存放高亮的各种规则

    //使用正则表达式匹配
    QRegularExpression commentStartExpression;
    QRegularExpression commentEndExpression;

    //字符的格式
    QTextCharFormat keywordFormat;
    QTextCharFormat classFormat;
    QTextCharFormat singleLineCommentFormat;
    QTextCharFormat multiLineCommentFormat;
    QTextCharFormat quotationFormat;
    QTextCharFormat functionFormat;
};
Highlighter::Highlighter(QTextDocument *parent)
    :QSyntaxHighlighter(parent)
{
    HighlightingRule rule;
    keywordFormat.setForeground(Qt::darkBlue);
    keywordFormat.setFontWeight(QFont::Bold);
    QStringList keywordPatterns;
    keywordPatterns << "\\bchar\\b" << "\\bclass\\b"
                    << "\\bconst\\b" << "\\bdouble\\b"
                    << "\\benum\\b" << "\\bexplicit\\b"
                    << "\\bfriend\\b" << "\\binline\\b"
                    << "\\bint\\b" << "\\blong\\b"
                    << "\\bnamespace\\b" << "\\boperator\\b"
                    << "\\bprivate\\b" << "\\bprotected\\b"
                    << "\\bpublic\\b" << "\\bshort\\b"
                    << "\\bsignals\\b" << "\\bsigned\\b"
                    << "\\bslots\\b" << "\\bstatic\\b"
                    << "\\bstruct\\b" << "\\btemplate\\b"
                    << "\\btypedef\\b" << "\\btypename\\b"
                    << "\\bunion\\b" << "\\bunsigned\\b"
                    << "\\bvirtual\\b" << "\\bvoid\\b"
                    << "\\bvolatitle\\b" << "\\bbool\\b";
    //保存c++语法中的关键字的匹配规则
    foreach (const QString& pattern, keywordPatterns) {
        rule.pattern = QRegularExpression(pattern);
        rule.format = keywordFormat;
        highlightingRules.append(rule);
    }

    //类名匹配规则以Q开头的
    classFormat.setFontWeight(QFont::Bold);
    classFormat.setForeground(Qt::darkMagenta);
    rule.pattern = QRegularExpression("\\bQ[A-Za-z]+\\b");
    rule.format = classFormat;
    highlightingRules.append(rule);

    //有注释的匹配规则
    singleLineCommentFormat.setForeground(Qt::red);
    rule.pattern = QRegularExpression("//[^\n]*");
    rule.format = singleLineCommentFormat;
    highlightingRules.append(rule);

    //多行注释
    multiLineCommentFormat.setForeground(Qt::red);

    //头文件匹配规则
    quotationFormat.setForeground(Qt::darkGreen);
    rule.pattern = QRegularExpression("\".*\"");
    rule.format = quotationFormat;
    highlightingRules.append(rule);

    //函数名称匹配规则
    functionFormat.setFontItalic(true);
    functionFormat.setForeground(Qt::blue);
    rule.pattern = QRegularExpression("\\b[A-Za-z0-9]+(?=\\()");
    rule.format = functionFormat;
    highlightingRules.append(rule);

    //注释开始的匹配
    commentStartExpression = QRegularExpression("/\\*");
    //注释结束的匹配
    commentEndExpression = QRegularExpression("\\*/");
}

void Highlighter::highlightBlock(const QString &text)
{
    foreach (const HighlightingRule &rule, highlightingRules) {
        //对文本进行正则表达式匹配 并返回匹配到的第一个匹配结果的迭代器
        QRegularExpressionMatchIterator matchIterator =
                rule.pattern.globalMatch(text);
        while (matchIterator.hasNext()) {
            /*
             *QRegularExpressionMatch类提供了根据字符串匹配QRegularExpression的结果。
             */
            QRegularExpressionMatch match = matchIterator.next();
            qDebug() << text << " <<<>>>> " << match.capturedTexts();
            //设置高亮的格式
            setFormat(match.capturedStart(0)
                      ,match.capturedEnd(0),
                                          rule.format);
        }
    }
    setCurrentBlockState(0);
    int startIndex = 0;
    if(previousBlockState() != 1)
        startIndex = text.indexOf(commentStartExpression);
    while (startIndex >= 0) {
        QRegularExpressionMatch match = commentEndExpression.match(text,startIndex);
        int endIndex = match.capturedStart();
        int commentLength = 0;
        if(endIndex == -1){
            setCurrentBlockState(1);
            commentLength = text.length() - startIndex;
        }else{
            commentLength = endIndex - startIndex +
                    match.capturedLength();
        }
        setFormat(startIndex,commentLength,multiLineCommentFormat);
        startIndex = text.indexOf(commentStartExpression,
                                  startIndex+commentLength);
    }
}
void MainWindow::setupEditor()
{
    QFont font;
    font.setFamily("Courier");
    font.setFixedPitch(true);
    font.setPointSize(10);

    editor = new QTextEdit;
    editor->setFont(font);

    //这里先把自定义的注册进去 告诉文档对象 使用这个进行高亮操作
    hightlighter = new Highlighter(editor->document());

    QFile file(":/src/mainwindow.h");
    if(file.open(QIODevice::ReadOnly|QIODevice::Text))
        editor->setPlainText(file.readAll());
    else
        qDebug() << "11111";
}

4、QTextCursor:提供一个API来访问和修改QTextDocuments

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    QTextEdit *textEdit = new QTextEdit(QString("hello world!hello Qt!"));
    setCentralWidget(textEdit);
    resize(400,300);

    //先拿到光标对象
    QTextDocument *doc = textEdit->document();
    QTextCursor *cursor = new QTextCursor(doc);

    qDebug() << "anchor=" << cursor->anchor() << " position=" << cursor->position();
    qDebug() << "atBlockEnd=" << cursor->atBlockEnd() << " atBlockStart="<< cursor->atBlockStart();
    qDebug() << "atEnd=" << cursor->atEnd() << " atStart="<< cursor->atStart();

    //编辑操作
    cursor->beginEditBlock();
    cursor->insertText("This is ");
    cursor->insertText("Insert ");
    cursor->endEditBlock();

    //返回光标所在的block的number
    qDebug() << "blockNumber=" << cursor->blockNumber();

    //返回光标所在行的列号
    qDebug() << "columnNumber=" << cursor->columnNumber();

    qDebug() << "hasComplexSelection=" << cursor->hasComplexSelection();
    //返回是否选择了内容
    qDebug() << "hasSelection=" << cursor->hasSelection();

    //在当前光标的位置插入一个空的block 相当于换行的操作
    cursor->insertBlock();

    //插入一个html文本
    cursor->insertHtml("<font color='red'>insertHtml</font>");
    cursor->insertBlock();
    //插入一个图片
    cursor->insertImage(":/image/任务管理-我的任务-任务查询查询不到已经创建的任务.png");
    qDebug() << "isNull=" << cursor->isNull();
    cursor->insertBlock();

    cursor->joinPreviousEditBlock();
    cursor->insertHtml("</b><font color='blue'>joinPreviousEditBlock</font></b>");
    cursor->endEditBlock();

    qDebug() << "keepPositionOnInsert="<<cursor->keepPositionOnInsert();

    //把光标移动到开头
    cursor->movePosition(QTextCursor::StartOfLine);
    //移动光标不选择
    cursor->movePosition(QTextCursor::EndOfWord,QTextCursor::MoveAnchor);
    //移动光标并且选择移动范围内的内容
    cursor->movePosition(QTextCursor::EndOfLine,QTextCursor::KeepAnchor);
    //界面要显示出来需要设置一下
    textEdit->setTextCursor(*cursor);

    //光标在block中的位置
    qDebug()<< "positionInBlock=" << cursor->positionInBlock() <<
               " " << cursor->position()-cursor->block().position();

    //删除选中的文字
    cursor->removeSelectedText();

    //根据选中类型来选中文档中的内容
//    cursor->select(QTextCursor::Document);
    cursor->select(QTextCursor::WordUnderCursor);
    //更新下光标 才能看出来是不是选中了
    textEdit->setTextCursor(*cursor);

    //返回选中的位置
    qDebug() << "selectionStart=" << cursor->selectionStart()
             << " selectionEnd=" << cursor->selectionEnd();

    //是否让光标不随着插入的文本移动,始终保持插入前的位置不变 默认是false
    cursor->setKeepPositionOnInsert(false);

    //使用m指定的MoveMode将光标移动到pos指定的文档中的绝对位置。光标位于字符之间。
    cursor->setPosition(1,QTextCursor::MoveAnchor);
    //更新
    textEdit->setTextCursor(*cursor);
}

5、QTextDocument:核心类,保存富文本数据

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    QTextEdit *edit = new QTextEdit;
    QTextDocument *doc = edit->document();
    //获得根框架
    QTextFrame *root_frame = doc->rootFrame();
    //获得根框架的格式
    QTextFrameFormat root_frame_format = root_frame->frameFormat();
    root_frame_format.setBorderBrush(Qt::darkBlue);//设置边框颜色
    root_frame_format.setBorder(5);//设置边框大小
    root_frame->setFrameFormat(root_frame_format);

    //自定义一个框架格式
    QTextFrameFormat frame_format;
    frame_format.setBackground(Qt::yellow);//设置背景色
    frame_format.setMargin(10);//设置外部的边距
    frame_format.setPadding(5);//设置内部的填充
    frame_format.setBorder(2);//设置边框宽度
    frame_format.setBorderStyle(QTextFrameFormat::BorderStyle_Solid);//设置边框样式
    //设置这个自定义框架是在哪个位置
    frame_format.setPosition(QTextFrameFormat::FloatRight);//右侧
    //根据宽度类型来设置该框架的宽度
    frame_format.setWidth(QTextLength(QTextLength::PercentageLength,40));//宽度设置

    QTextCursor cursor = edit->textCursor();

    cursor.insertText("A company");
    cursor.insertBlock();
    cursor.insertText("321 City Street");
    cursor.insertBlock();
    cursor.insertFrame(frame_format);
    cursor.insertText("Industry Park");
    cursor.insertBlock();
    cursor.insertText("Another country");
    edit->setTextCursor(cursor);

    //把内容遍历出来
    for(auto block=root_frame->begin();!block.atEnd(); ++block){
        if(block.currentBlock().isValid()){
            qDebug() << block.currentBlock().text();
        }else if(block.currentFrame()){
            qDebug() << "是一个框架";
            for(auto frame_block = block.currentFrame()->begin(); !frame_block.atEnd(); ++frame_block){
                if(frame_block.currentBlock().isValid()){
                    qDebug() << frame_block.currentBlock().text();
                }else{
                    qDebug() << "else";
                }
            }
        }
    }

    //遍历所以block 包括每个frame中默认的空的
    qDebug() << "doc->blockCount()=" << doc->blockCount();
    QTextBlock block = doc->firstBlock();
    for(int i = 0; i < doc->blockCount(); ++i){
        qDebug()<< QString("block num:%1 block first line number:%2 block length:%3 text:")
                   .arg(i).arg(block.firstLineNumber()).arg(block.length())
                   << block.text();
        block = block.next();
    }

    //获取第2个block的开头
    QTextBlock insert_block = doc->firstBlock().next();
    cursor.setPosition(insert_block.position()+insert_block.length()-1);
    cursor.insertText("change cursor postion and insert");

    //将光标设置到第3个block的开头
//    cursor.setPosition(insert_block.position()+insert_block.length());
    cursor.setPosition(insert_block.next().position());
    cursor.insertText("change cursor postion and insert");

    setCentralWidget(edit);
    resize(400,300);
}
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    //先不用界面展示
    QTextDocument *doc = new QTextDocument;
    QTextCursor *cursor = new QTextCursor(doc);
    //文档本身是有一个文本块的 可以通过框架来获得
    QTextFrame *root_frame = doc->rootFrame();
    QTextBlock block = root_frame->begin().currentBlock();
    qDebug() << "此时文本块="<<block.text();
    //通过光标向文本块中插入文本
    cursor->insertText("aaa");
    block = root_frame->begin().currentBlock();
    qDebug() << "插入后的文本块="<<block.text();
    //插入一个新的文本块 光标换行了 然后在此block中插入数据
    cursor->insertBlock();
    cursor->insertText("bbbb");
    for(int i = 0; i < 10; ++i){
        cursor->insertText("cccccccccccccccccccc");
    }
    qDebug() << "第2个block的长度="<<root_frame->begin().currentBlock().next().length();
    qDebug() << "第2个block的行数="<<root_frame->begin().currentBlock().next().lineCount();
    qDebug() << "第2个block的blockNumber="<<root_frame->begin().currentBlock().next().blockNumber();
    //插入一个自定义的frame 插入之后 除了frame自带一个block,在frame的最后还有一个blcok
    QTextFrameFormat format = root_frame->frameFormat();
    format.setBorder(3);
    cursor->insertFrame(format);
    cursor->setPosition(root_frame->begin().currentBlock().next().next().position());
    cursor->insertText("dddd");
    cursor->setPosition(root_frame->begin().currentBlock().next().next().next().position());
    cursor->insertText("eeee");
    qDebug() << doc->blockCount();


    QTextEdit *edit = new QTextEdit;
    edit->setDocument(doc);
    edit->setTextCursor(*cursor);
    setCentralWidget(edit);
    resize(300,200);
}

6、QTextDocumentFragment:表示来自QTextDocument的富文本的片段,可以将该片段通过cursor插入到文档中去,并且只有当文档中的某个内容被选中时,可以通过获取选中的片段来解析获取选中的内容

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    QTextDocument *doc = new QTextDocument;
    QTextCursor *cursor = new QTextCursor(doc);
    QTextDocumentFragment fragment = QTextDocumentFragment::fromPlainText("hello world");
//向文档中插入片段    
cursor->insertFragment(fragment);
//获取选中的片段
    cursor->select(QTextCursor::Document);
    qDebug() << cursor->selection().toPlainText();
    cursor->clearSelection();
    cursor->insertBlock();
    fragment = QTextDocumentFragment::fromHtml("<font color='red'>hello Qt</font>");
    cursor->insertFragment(fragment);
    cursor->select(QTextCursor::LineUnderCursor);
    qDebug() << cursor->selection().toHtml();
    cursor->clearSelection();

    QTextEdit *edit = new QTextEdit;
    edit->setDocument(doc);
    edit->setTextCursor(*cursor);
    setCentralWidget(edit);
}

7、QTextDocumentWriter:与格式无关的接口,用于将QTextDocument写入文件或其他设备

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    //获取支持的写入格式
    qDebug() << QTextDocumentWriter::supportedDocumentFormats();//("HTML", "ODF", "plaintext")
    QTextDocumentWriter writer("a.txt");
    QTextCodec* gb2312Codec = QTextCodec::codecForName("gb2312");
    writer.setCodec(gb2312Codec);
    writer.write(QTextDocumentFragment::fromPlainText("你好啊"));

    //把写入的文件读出来
    QFile file("a.txt");
    file.open(QIODevice::ReadOnly);
    QByteArray array = file.readAll();
    qDebug() << gb2312Codec->toUnicode(array);

    QTextDocumentWriter writerOdf("a.doc","odf");//xlsx xls 试下了 好像不行 有可能方法错了
    writerOdf.write(QTextDocumentFragment::fromPlainText("你好啊"));

    QTextDocumentWriter writerHtml("a.html","HTML");
    writerHtml.write(QTextDocumentFragment::fromHtml("<b><font color='red'>你好啊</font></b>"));
}

8、QTextBlockFormat: 保存QTextDocument中的文本块的格式信息。

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    QTextDocument *doc = new QTextDocument;
    QTextCursor *cursor = new QTextCursor(doc);

    //自定义一个blcok格式
    QTextBlockFormat blockFormat;
    blockFormat.setAlignment(Qt::AlignRight);//右对齐
    blockFormat.setBackground(QBrush(Qt::yellow));//背景色
    blockFormat.setBottomMargin(10);//外部距离底部的空间
    blockFormat.setForeground(QBrush(Qt::lightGray));//前景色
    blockFormat.setIndent(4);//缩进
    blockFormat.setLayoutDirection(Qt::RightToLeft);//文字从右到左
    blockFormat.setLeftMargin(10);//外部距离左边的空间
    blockFormat.setLineHeight(50,QTextBlockFormat::LineDistanceHeight);//这将在行之间添加指定的高度50像素点
    blockFormat.setNonBreakableLines(true);//设置是不可以被打乱的
    blockFormat.setTopMargin(50);
    blockFormat.setRightMargin(100);
    blockFormat.setTextIndent(10);//为块中的第一行设置缩进。
    cursor->insertBlock(blockFormat);
    cursor->insertText("这几天权健新闻火了,昔日风光无比的保健品大拿,今日面临着各项指控,高法还指认其进涉嫌传销,可叹法网恢恢疏而不漏啊。今天做生意,讲的是商业模式,互联网的发展形成了很多种商业模式,比如社交,比如B2B,B2C等,但是,在互联网大行其道之前,中国常看到的就是一种直销的商业模式,直销接着就出来变种,变成了传销,直销和传销都是拉人头,只不过直销还是有商品为主,而传销感觉商品只是其中一个引子而已,纯粹就是赚人头费,层层的组织,最终让人们死心塌地活在传销生态圈里不能自拔,曾几何时,见面就跟人谈产品,让人无比侧目。");
    cursor->insertBlock(QTextBlockFormat());
    cursor->insertText("这个是正常的");

    QTextEdit *edit = new QTextEdit;
    edit->setDocument(doc);
    edit->setTextCursor(*cursor);
    setCentralWidget(edit);
    resize(500,400);
}

9、QTextCharFormat:保存QTextDocument中的字符的格式信息。

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    QTextEdit *edit = new QTextEdit;
    QTextDocument *doc = edit->document();
    QTextCursor *cursor = new QTextCursor(doc);

    //自定义一个类型
    QTextCharFormat charFormat;
    charFormat.setAnchorHref("http://example.com/index.html");
    charFormat.setAnchor(true);
    QFont font;
    font.setBold(true);
    font.setUnderline(true);
    charFormat.setFont(font);
    charFormat.setToolTip("这是hello world");

    cursor->insertBlock();
    cursor->insertText("hello world",charFormat);
    edit->setTextCursor(*cursor);
    setCentralWidget(edit);
    resize(400,100);
}

10、QTextFormat:保存QTextDocument中文本的格式信息。QTextFormat是一个通用类,用于描述QTextDocument部分内容的格式。派生类QTextCharFormat、QTextBlockFormat、QTextListFormat和QTextTableFormat通常更有用,它们描述了应用于文档特定部分的格式。

11、QTextFrameFormat:保存QTextDocument中的框架的格式信息。

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    QTextEdit *edit = new QTextEdit;
    QTextDocument *doc = edit->document();
    QTextCursor *cursor = new QTextCursor(doc);

    cursor->insertText("这是我的框架格式");
    cursor->insertBlock();
    //自定义格式
    QTextFrameFormat format;
    format.setBackground(QBrush(Qt::blue));
    format.setBorder(3);
    format.setBorderBrush(QBrush(Qt::red));
    format.setTopMargin(5);
    format.setBottomMargin(5);
    format.setLeftMargin(5);
    format.setRightMargin(5);
//    format.setHeight(QTextLength(QTextLength::FixedLength,100));
    format.setPadding(30);
    format.setPosition(QTextFrameFormat::FloatRight);
    format.setWidth(QTextLength(QTextLength::PercentageLength,40));
    format.setBorderStyle(QTextFrameFormat::BorderStyle_Dotted);
    cursor->insertFrame(format);
    cursor->insertText("啊啊啊啊啊啊啊");
    setCentralWidget(edit);
    edit->setTextCursor(*cursor);
    resize(400,300);
}

这张图特别形象说明了文字或者框架的围绕布局

12、QTextImageFormat:保存QTextDocument中的图像的格式信息。

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    QTextDocument *doc = new QTextDocument;
    QTextCursor *cursor = new QTextCursor(doc);

    //自定义一个图片格式
    QTextImageFormat imageFormat;
    QImage image(":/image/v2-e687e8a3299301852036625042c0d21f_hd.jpg");
    imageFormat.setName(":/image/v2-e687e8a3299301852036625042c0d21f_hd.jpg");
    imageFormat.setHeight(image.height()*0.3);
    imageFormat.setWidth(image.width()*0.3);
    cursor->insertBlock();
    cursor->insertImage(imageFormat);

    QTextEdit *edit = new QTextEdit;
    edit->setDocument(doc);
    edit->setTextCursor(*cursor);
    setCentralWidget(edit);
    resize(400,300);
}

13、QTextLength:表示了QTextDocument中不同类型的文本长度。使用方法详见上面

14、QTextListFormat:保存QTextDocument中的列表的格式信息。

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    QTextEdit *edit = new QTextEdit;
    QTextDocument *doc = edit->document();
    QTextCursor *cursor = new QTextCursor(doc);
    cursor->beginEditBlock();
    cursor->insertText("hello world");
    cursor->insertText("aaaa");
    cursor->endEditBlock();
    QTextBlock listblock = cursor->block();
    cursor->insertBlock();
    cursor->setPosition(listblock.length()-1);
    //定义一个TextListFormat
    QTextListFormat format;
    format.setBackground(QBrush(Qt::blue));
    format.setIndent(1);//设置缩进
    format.setLayoutDirection(Qt::RightToLeft);//设置文字方向
    format.setStyle(QTextListFormat::ListDecimal);//设置开头以数字表示
    format.setNumberPrefix("(");//前缀
    format.setNumberSuffix(")");//后缀
    QTextList *list = cursor->insertList(format);
    cursor->insertText("bbbb");
    //但是如何跳出这个textlist呢?
    cursor->setPosition(cursor->block().next().position());

    edit->setTextCursor(*cursor);
    setCentralWidget(edit);
    resize(300,200);
}

15、QTextTableCellFormat:保存QTextDocument中的表格单元的格式信息

16、QTextTableFormat:保存QTextDocument中的表格的格式信息

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    QTextDocument *doc = new QTextDocument;
    QTextCursor cursor = QTextCursor(doc);
    cursor.insertText("hello world");
    //根据表格式来创建表
    QTextTableFormat tableFormat;
    tableFormat.setBackground(QBrush(Qt::yellow));
    tableFormat.setBorder(2);
    tableFormat.setBorderStyle(QTextFrameFormat::BorderStyle_Solid);
    //表格的对齐方式 注意不是表格内的内容
    tableFormat.setAlignment(Qt::AlignCenter);
    tableFormat.setPadding(2);
    tableFormat.setCellSpacing(3);

    cursor.insertTable(10,4,tableFormat);

    QTextEdit *edit = new QTextEdit;
    edit->setDocument(doc);
    edit->setTextCursor(cursor);
    setCentralWidget(edit);
    resize(300,200);
}

17、QTextInlineObject:表示QAbstractTextDocumentLayout及其实现中的内联对象。通常,您不需要创建QTextInlineObject。QAbstractTextDocumentLayout在实现自定义布局时使用它来处理内联对象。

18、QTextLayout:用于布局和呈现文本。QTextLayout可用于创建具有给定宽度的QTextLine实例序列,并可在屏幕上独立定位它们。一旦布局完成,这些线条就可以绘制在绘图设备上。

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    resize(300,200);
}

MainWindow::~MainWindow()
{

}

void MainWindow::paintEvent(QPaintEvent *event)
{
    QTextLayout *layout = new QTextLayout;
    //要进行布局的文本内容
    layout->setText("hello world 11111111111111111111111111111111");
    //一般设置可以缓存
    layout->setCacheEnabled(true);
    //更改下文本的字体格式
    QFont font;
    font.setUnderline(true);
    layout->setFont(font);
    //开始布局
    layout->beginLayout();
    int height = 0;
    int lineWidth = 100;
    int startPoint = 0;
    while (1) {
        //先创建一个行
        QTextLine line = layout->createLine();
        if (!line.isValid())
            break;

        //设置这一行的文本宽度
        line.setLineWidth(lineWidth);
        //高度需要叠加计算 否则文字会被布局到一起
        height += 10;
        //设置行的起点和高度
        line.setPosition(QPointF(30*(++startPoint), height));
        //计算最终的高度
        height += line.height();
    }

    layout->endLayout();
    QPainter painter(this);
    layout->draw(&painter, QPoint(0, 50));
}

19、QTextLine:表示QTextLayout中的一行文本。

20、QTextList:提供QTextDocument中修饰过的项目列表。

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    QTextEdit *edit = new QTextEdit;
    QTextDocument *doc = edit->document();
    QTextCursor *cursor = new QTextCursor(doc);
    cursor->insertText("hello world");
    //有2中创建QTextList的方式
    //createList函数:获取光标当前block的内容,并将其转换为新列表的第一项。
    cursor->createList(QTextListFormat::ListDisc);
    cursor->insertText("aaaa");
    //继续在此列表中添加数据
    cursor->insertBlock();
    cursor->insertText("bbbb");
    //insertList函数:在文档的光标位置插入一个block,并将其作为列表中的第一项。
    cursor->insertList(QTextListFormat::ListCircle);
    cursor->insertText("hello Qt");
    cursor->insertBlock();
    cursor->insertText("cccc");
    edit->setTextCursor(*cursor);
    setCentralWidget(edit);
    resize(400,300);
}

21、QTextBlock:为QTextDocument中的文本片段提供了一个容器。

22、QTextBlockGroup:为QTextDocument中的文本块提供了一个容器。

23、QTextBlockUserData:将自定义数据与文本块相关联。

24、QTextFragment:使用一个QTextCharFormat保存QTextDocument中的一段文本。

25、QTextFrame:表示QTextDocument中的一个框架。

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    QTextEdit *edit = new QTextEdit;
    QTextDocument *doc = edit->document();
    QTextCursor *cursor = new QTextCursor(doc);
    cursor->insertText("aaaa");
    cursor->insertBlock();

    //必须先定义一个框架格式
    QTextFrameFormat frameFormat;
    frameFormat.setBorder(3);
    //创建在文档中添加框架
    QTextFrame *frame = cursor->insertFrame(frameFormat);
    cursor->insertText("bbbb");
    frameFormat.setBorder(2);
    frameFormat.setBorderBrush(QBrush(Qt::red));
    frameFormat.setBorderStyle(QTextFrameFormat::BorderStyle_Dotted);
    QTextFrame *childFrame = cursor->insertFrame(frameFormat);
    cursor->insertText("cccc");
    qDebug()<< "子框架个数:"<<frame->childFrames().size();
    cursor->setPosition(cursor->block().next().position());
    cursor->insertText("dddd");

    //返回框架中的第一个光标位置。
    QTextCursor frameCursor = childFrame->parentFrame()->firstCursorPosition();
    edit->setTextCursor(frameCursor);
    //返回框架中的最后的光标位置。
    frameCursor = childFrame->parentFrame()->lastCursorPosition();
    edit->setTextCursor(frameCursor);
    setCentralWidget(edit);
//    edit->setTextCursor(*cursor);
    resize(300,200);
}

26、QTextObject:用于不同类型对象的基类,这些对象可以将QTextDocument的各个部分组合在一起。

27、QTextFrame::iterator: 迭代器类为读取QTextFrame的内容提供了一个迭代器。

28、QTextBlock::iterator: 为读取QTextBlock的内容提供了一个迭代器。

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    QTextEdit *edit = new QTextEdit;
    QTextDocument *doc = edit->document();
    QTextCursor cursor = edit->textCursor();
    cursor.insertText("hello world! hello Qt!");
    cursor.insertText("111222333444");
    QTextBlock block = cursor.block();//doc->firstBlock();
    QTextBlock::iterator it;
    for(it = block.begin(); !it.atEnd(); ++it){
        QTextFragment fragment = it.fragment();
        if(fragment.isValid())
            qDebug() << fragment.text();
    }
    setCentralWidget(edit);
    edit->setTextCursor(cursor);
    resize(300,200);
}

29、QTextOption:可以设置富文本的一般属性。

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    QTextEdit *edit = new QTextEdit;
    QTextDocument *doc = edit->document();
    doc->setPlainText("hello world!111111");

    //定义一个封装文本格式的对象
    QTextOption option;
//    option.setAlignment(Qt::AlignCenter);
    option.setTextDirection(Qt::RightToLeft);
    option.setWrapMode(QTextOption::WrapAnywhere);
    doc->setDefaultTextOption(option);

    setCentralWidget(edit);
    resize(300,200);
}

30、QTextTable:表示QTextDocument中的一个表。

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    QTextEdit *edit = new QTextEdit;
    QTextDocument *doc = edit->document();
    QTextCursor cursor = edit->textCursor();
    cursor.insertText("hello world");
    //不含表格式创建 光标落在第一行第一列中
    QTextTable *table = cursor.insertTable(5,5);
    //右侧插入2列
    table->insertColumns(4,2);
    //下边插入2行
    table->insertRows(4,2);
    //合并单元格 指定下标
    table->mergeCells(0,0,2,5);
    cursor.insertText("合并000000000000000000000000");
    //合并单元格 合并由提供的游标选择的单元格。
    cursor.movePosition(QTextCursor::NextRow);
    cursor.movePosition(QTextCursor::NextCell,QTextCursor::KeepAnchor);
    table->mergeCells(cursor);
    cursor.insertText("合并111111111111111111111111");
    //将个单元格分割成多行多列 只可能分割跨多个行或列的单元格,例如使用mergeCells()合并的行。
    table->splitCell(0,0,1,2);

    //设置一个空的格式
    table->setFormat(QTextTableFormat());


    //光标如何跳出这个表
//    for(int i = 1; i < table->rows(); ++i)
//        cursor.movePosition(QTextCursor::NextRow);
//    for(int i = 1; i < table->columns(); ++i)
//        cursor.movePosition(QTextCursor::NextCell);
//    cursor.movePosition(QTextCursor::NextBlock);
//    cursor.insertBlock();
//    cursor.insertText("aaaa");

    setCentralWidget(edit);
    edit->setTextCursor(cursor);
    resize(300,200);
}

31、QTextTableCell:表示QTextTable中的单元格的属性。

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    resize(300,200);
    QTextEdit *edit = new QTextEdit;
    QTextDocument *doc = edit->document();
    QTextCursor cursor = edit->textCursor();
    QVector<QTextLength> vector;
    for(int i = 0; i < 5; ++i)
        vector << QTextLength(QTextLength::PercentageLength,20);
    QTextTableFormat format;
    format.setColumnWidthConstraints(vector);
    format.setCellSpacing(1);
    QTextTable *table = cursor.insertTable(5,5,format);

    //赋值
    for(int i = 0; i < 5; ++i){
        for(int j = 0; j < 5; ++j){
            //设置下字体格式
            QTextBlockFormat blockFormat;
            blockFormat.setAlignment(Qt::AlignRight);
            cursor.setBlockFormat(blockFormat);
            QTextCharFormat charFormat;
            charFormat.setFontFamily("宋体");
            charFormat.setFontItalic(true);
            charFormat.setFontUnderline(true);
            cursor.setCharFormat(charFormat);
            cursor.insertText(QString("row%1,col%2").arg(i).arg(j));
            QTextTableCell cell = table->cellAt(cursor);
            qDebug() << "(" << cell.row() << "," << cell.column() << ")";
            QTextCursor tmp = cell.firstCursorPosition();
            qDebug() << "first tmp = " << tmp.position();
            tmp = cell.lastCursorPosition();
            qDebug() << "last tmp = " << tmp.position();
            if(j == 4)
                continue;
            cursor.movePosition(QTextCursor::NextCell);
        }
        if(i == 4)
            continue;
        cursor.movePosition(QTextCursor::NextRow);
    }
    edit->setTextCursor(cursor);
    setCentralWidget(edit);
}

32、QPlainTextDocumentLayout:为QTextDocument实现纯文本布局

33、QPlainTextEdit:一个小部件,用于编辑和显示纯文本。

class LineNumberArea;

class CodeEditor : public QPlainTextEdit
{
    Q_OBJECT

public:
    CodeEditor(QWidget *parent = 0);
    ~CodeEditor();

    void lineNumberAreaPaintEvent(QPaintEvent *event);
    int lineNumberAreaWidth();

protected:
    void resizeEvent(QResizeEvent *event) override;

private slots:
    void updateLineNumberAreaWidth(int newBlockCount);
    void highlightCurrentLine();
    void updateLineNumberArea(const QRect & , int);
private:
    QWidget *lineNumberArea;
};

class LineNumberArea : public QWidget
{
public:
    LineNumberArea(CodeEditor *editor):QWidget(editor)
    {
         codeEditor = editor;
    }

    QSize sizeHint()const override
    {
        return QSize(codeEditor->lineNumberAreaWidth(),0);
    }

protected:
    void paintEvent(QPaintEvent *event) override
    {
        codeEditor->lineNumberAreaPaintEvent(event);
    }

private:
    CodeEditor *codeEditor;
};
CodeEditor::CodeEditor(QWidget *parent)
    : QPlainTextEdit(parent)
{
    //创建行号显示控件
    lineNumberArea = new LineNumberArea(this);

    //当换行时更新行号
    connect(this,SIGNAL(blockCountChanged(int)),
            this,SLOT(updateLineNumberAreaWidth(int)));

    connect(this,SIGNAL(updateRequest(QRect,int)),
            this,SLOT(updateLineNumberArea(QRect,int)));
    connect(this,SIGNAL(cursorPositionChanged()),
            this, SLOT(highlightCurrentLine()));

    updateLineNumberAreaWidth(0);
    highlightCurrentLine();
}

CodeEditor::~CodeEditor()
{

}

void CodeEditor::lineNumberAreaPaintEvent(QPaintEvent *event)
{
    qDebug() << event->rect();
    QPainter painter(lineNumberArea);
    painter.fillRect(event->rect(),Qt::lightGray);

    QTextBlock block = firstVisibleBlock();
    int blockNumber = block.blockNumber();
    int top = (int)blockBoundingGeometry(block).translated(contentOffset()).top();
    int bottom = top + (int)blockBoundingRect(block).height();

    while (block.isValid() && top <= event->rect().bottom()) {
        if(block.isVisible() && bottom >= event->rect().top()){
            QString number = QString::number(blockNumber+1);
            painter.setPen(Qt::black);
            painter.drawText(0,top,lineNumberArea->width(),fontMetrics().height(),
                             Qt::AlignRight,number);
        }
        block = block.next();
        top = bottom;
        bottom = top + (int)blockBoundingRect(block).height();
        ++blockNumber;
    }
}

int CodeEditor::lineNumberAreaWidth()
{
    int digits = 1;
    int max = qMax(1,this->blockCount());
    while (max >= 10) {
        max /= 10;
        ++digits;
    }
    int space = 3+fontMetrics().width(QLatin1Char('9'))*digits;
    return space;
}

void CodeEditor::resizeEvent(QResizeEvent *event)
{
    QPlainTextEdit::resizeEvent(event);
    QRect cr = contentsRect();
    lineNumberArea->setGeometry(QRect(cr.left(),
                               cr.top(),lineNumberAreaWidth(),
                               cr.height()));
}

void CodeEditor::updateLineNumberAreaWidth(int newBlockCount)
{
    //更新编辑框距离左边的间距
    setViewportMargins(lineNumberAreaWidth(),0,0,0);
}

void CodeEditor::highlightCurrentLine()
{
    QList<QTextEdit::ExtraSelection> extraSelections;
    if(!isReadOnly()){
        //ExtraSelection结构提供了一种为文档中给定的选择指定字符格式的方法
        QTextEdit::ExtraSelection selection;
        QColor lineColor = QColor(Qt::yellow).lighter(160);
        selection.format.setBackground(lineColor);
        //FullWidthSelection 表示在选定的字符格式上设置时,将显示选定文本的整个宽度。
        selection.format.setProperty(QTextFormat::FullWidthSelection,true);
        selection.cursor = textCursor();
        selection.cursor.clearSelection();
        extraSelections.append(selection);
    }
    /*
     * 此函数允许用指定的颜色(指定为选择)临时标记文档中的某些区域。这可能非常有用,
     * 例如在编程编辑器中,用给定的背景颜色标记一整行文本以表明断点的存在。
     */
    setExtraSelections(extraSelections);
}

void CodeEditor::updateLineNumberArea(const QRect &rect, int dy)
{
    qDebug() << rect << " "<<dy;
    if(dy){
        //让行号跟随编辑框滚动 并且重新绘制
        lineNumberArea->scroll(0,dy);
    }else{
        lineNumberArea->update(0,rect.y(),lineNumberArea->width(),rect.height());
    }

    if(rect.contains(viewport()->rect()))
        updateLineNumberAreaWidth(0);
}
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    QPlainTextEdit *edit = new QPlainTextEdit("hello world111222333");
    //设置换行格式
//    edit->setLineWrapMode(QPlainTextEdit::NoWrap);//不换行
    edit->setWordWrapMode(QTextOption::WrapAnywhere);//任意处换行
    //插入文本 在当前光标前面
    edit->insertPlainText("555666");
    //追加文本 在文档最后 并且换行追加
    edit->appendPlainText("777888");
    edit->appendPlainText("999000");

    //查找并且选中文本
    QTextCursor cursor = edit->textCursor();
    edit->find("888");
    setCentralWidget(edit);
    resize(300,200);
}

34、QTextBrowser:提供了具有超文本导航的富文本浏览器。

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{

    QTextBrowser *browser = new QTextBrowser;
    browser->setAttribute(Qt::WA_DeleteOnClose);
    setCentralWidget(browser);
    //可以当做编辑框使用
//    browser->setReadOnly(false);
//    browser->setEnabled(true);
    /*
     * 指定QTextBrowser是否应该使用QDesktopServices::openUrl()自动打开指向外部源的链接,
     * 而不是发出锚点单击信号。如果链接的模式既不是文件也不是qrc,则视为外部链接.
     */
    browser->setOpenExternalLinks(true);//设置为支持使用外部程序打开url
    /*
     * 此属性指定QTextBrowser是否应自动打开用户试图通过鼠标或键盘激活的链接。
     */
    browser->setOpenLinks(true);
    /*
     * 此属性保存文本浏览器用于查找支持内容的搜索路径
     * QTextBrowser使用这个列表来定位图像和文档。
     */
    browser->setSearchPaths(QStringList()<<"F:/");
    /*
     * 此属性保存显示的文档的名称。
     * QTextBrowser尝试在当前源的searchPaths属性和目录的路径中查找具有指定名称的文档,
     * 除非该值是一个绝对文件路径。
     */
    //加载一个下载好的html来供文本浏览器使用
    QUrl url = QUrl::fromLocalFile("F:/【wei375653972的博客】Qt基础学习_成为QML大神_Qt常用类学习 - CSDN博客.html");
    browser->setSource(url);

    /*
     * 请注意,浏览器将自动处理到link指定位置的导航,除非将openLinks属性设置为false,
     * 或者在连接的槽中调用setSource()。此机制用于覆盖浏览器的默认导航特性。
     */
    connect(browser,&QTextBrowser::anchorClicked,[=](const QUrl &){
        qDebug() << url.url();
    });

    home = menuBar()->addAction("Home");
    connect(home,&QAction::triggered,browser,&QTextBrowser::home);
    back = menuBar()->addAction("Back");
    connect(back,&QAction::triggered,browser,&QTextBrowser::backward);
    close = menuBar()->addAction("Close");
    connect(close,&QAction::triggered,browser,&QTextBrowser::close);
    connect(browser,&QTextBrowser::destroyed,[=]{
        qDebug() << "被销毁了?";
    });
}

35、QTextEdit:一个小部件,用于编辑和显示纯文本和富文本。详见上面

猜你喜欢

转载自blog.csdn.net/wei375653972/article/details/85335020