Qt 富文本處理


富文本處理

所有的類圍繞 QTextDocument 展開, 它保證了用戶可以創建和修改 富文本塊, 而無須定義中間語言。
一個 QTextDocument 可以通過兩個接口操作, 一個是用於編輯的 Cusor based 接口, 一個是只讀的文檔結構樹。

Rich Text Document Structure

QTextDocument 是一個文檔的抽象, 它包括了文檔的內部結構, 並且能夠通過跟蹤變化以提供 undo / redo 操作。 Qt通過 block frame table 以及其他類的樹狀結構表示文檔。 Frame 和 table 用於組織其它結構, 而 block 包含實際內容。

QDocument 可以從 QTextEdit 中獲取, 也可以是用默認構造。 這樣可以保證 控件和 document的輕耦合。 一個空的文檔包括了一個 root frame , 它包括了一個空的block 。 table 是 frame 的一個 子類, 它的行和列都可以單獨包含 block。 富文本結構

  • Block 包含 fragment, 每一個fragment 都包含了 文字 和 字符的格式信息。文字格式信息包含於 block 和 character 兩個層面。
  • Character 包含了字體、文字顏色、字體加粗等信息, block 包含了 文字方向、排版以及背景色等信息。
  • Image 使用 fragment 表示。

QTextObject 的子類可以歸並文檔元素: QTextBlockGroup 可以歸並 block; QTextFrame 可以歸並 block 以及其它 元素。

一個frame 結構可以包括 多個 或者0個 frame,至少1個block; 它的 format 決定了frame在 頁面上如何被渲染和定位。使用 iterator 可以遍歷frame 結構,但是要注意 iterator 的數據類型是不確定的。

QTextList 是 QTextBlockGroup 的一個子類, 它並不是 把 list item 當作它的子元素, 而是提供了一系列用於操作list item的函數。 可以如下使用

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

The QTextCursor Interface

Cursor 可以通過一個構造函數創建, 也可以在 edit widget 中獲取。

cursor 可以以 block 為單位, 保存選區信息。

一個 document 里面可以有多個 cursor, 但是只有一個是可見的; paste 和 copy操作就是這樣實現的。 通過簡單的繼承, 可以實現很多復雜的操作。

Cursor 能夠追蹤它在 document 中的位置, 以及所在結構。

cursor一系列的 edit可以被打包, 這樣能夠在 redo 和 undo 中把它作為一個操作看待。一般使用 beginEditBlock 開始, endEditBlock 結束。

Cursor 的insert 有兩個級別。 分別是 block 級別, 和 document級別。 Block級別可以插入 block 、 fragment 、 image 、text等; document 級別 插入 frame 、 table、 list, 這個級別的插入會在當前 frame 內、 當前block 以后。

可以在當前塊中插入 當前文字格式 的字符串, 也可以插入自定義字符格式的字符串; 一旦在使用cursor 插入時使用了一個格式,那么這個格式會成為以后的 cursor 插入的默認格式,除非使用一個新的格式(替代了它)。

cursor.insertText(tr("Character formats"),headingFormat);
cursor.insertBlock();
cursor.insertText(tr("Text can be displayed in a variety of "
                              "different character formats. "), plainFormat);
cursor.insertText(tr("We can emphasize text by "));
cursor.insertText(tr("making it italic"), emphasisFormat);

Document Layouts
Document Layout 僅僅在文檔的展示、需要展示的變化發生時有意義。

QAbstractTextDocumentLayout 是文檔中管理所有 text layout 的抽象類。

富文本處理過程概述

常規的文本操作包括, 使用 QTextEdit 和 QTextBrowser 編輯文檔, 使用QTextDocument 創建文檔, 使用 QTextCursor 編輯文檔, 以及打印等。

QTextBrowser 提供對有超鏈接文本的展示。 如果在文末使用 #anchor, 在文本滾動顯示時會自動加載 anchor 所指內容。

QTextDocument 的查找是基於 QCursor 的。 如下:

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

Printing
QTextEdit 用於展示大文件在屏幕上可讀的部分, 使用和 web 瀏覽器相同的方法去渲染。 它沒有分頁的功能。

QTextDocument 提供了 print 函數, 以下代碼展示了如何使用 QPrinter 打印。

QTextDocument*document = editor->document();
QPrinter printer;
QPrintDialog*dlg =newQPrintDialog(&printer,this);
if (dlg->exec() !=QDialog::Accepted)
    return;
document->print(&printer);

Advanced Rich Text Processing
Qt 在處理文字時沒有對文件大小做出限制,因此這有可能導致你的應用在加載文件時失去響應。 也有一些其它問題也會導致程序的性能降低。 因此有以下幾個規則。

把大的段落分割成較小的段落。

把 文件中 block 的數目限制在 maximumBlockCount() 以內。

以塊為單位把文檔加載到 text edit, 如下。 因為很多時候text edit 都沒有必要加載一整個文檔。

textEdit.show();
textCursor.beginEditBlock();
for (int i =0; i <1000; ++i) {
    textCursor.insertBlock();
    textCursor.insertText(paragraphText.at(i));
}
textCursor.endEditBlock();

Supported HTML Subset

Qt 的 text widgets支持html4的語法子集, 具體可以參考 Qt Mannual - Supported HTML Subset 。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM