QTextEdit 總結


關於Qt的富文本處理, 可以參考文檔: Rich Text Processing

該文檔有人翻譯了一下(本來我想翻譯- -!), 參考Rich Text Processing富文本處理 

QTextEdit的組成比較復雜, 最好看看文檔了解一下Rich Text Document Structure

1. HTML形式操縱Qtextedit

  QTextEdit支持HTML的一個子集, 所以對於簡單的使用, 可以直接插入HTML代碼

  

editor->append("<img src=\"mydata://image.png\" />");

  通過插入html代碼, 可以實現圖片, 字體, 字號, 顏色等功能
 ps: QTextEdit中img標簽僅支持src, width, height三個屬性, 使用其他屬性會自動被Qt過濾掉, 即editor->toHtml()中無法找到

  可以通過正則來過濾toHtml()生成的代碼

  其他HTML支持, 參考Supported HTML Subset

2. 在QTextEdit中播放gif

  QTextEdit雖然直接img標簽, 但默認不播放gif, 也不會顯示gif的第一幀 (如果你不需要編輯功能的話, 其實可以用QWebView來查看)

  所以在QTextEdit中播放gif需要手動換幀. 

  QMovie內置了gif解析和定時器功能. 

  QTextDocument 使用addResource 把圖片資源加載進來, 然后通過QMovie->start啟動定時器, 不斷更新圖片資源

QString g_fileName = ":/test.gif";
QUrl g_url("TestImageTag"); 
void MyClass::InsertImage()
{
    QMovie* movie = new QMovie(this); 
    movie->setFileName(g_fileName);  
    movie->setCacheMode(QMovie::CacheNone);  

    //換幀時刷新  
    connect(movie, SIGNAL(frameChanged(int)), this, SLOT(OnAnimate(int)));  
    movie->start(); 
}

g_url 是自定義的標簽, 用來標記QTextDocument 中的resource

void MyClass::OnAnimate(int a)  
{  
    if (QMovie* movie = qobject_cast<QMovie*>(sender()))  
    {              
        document()->addResource(QTextDocument::ImageResource,   //替換圖片為當前幀  
                                g_url, movie->currentPixmap());     
          
        setLineWrapColumnOrWidth(lineWrapColumnOrWidth()); // 刷新顯示  
    }  
}  

addResource 指定ImageResource, 然后根據url, 若url已存在, 則更新資源, 若url不存在, 則添加資源

這樣就實現刷新gif的幀. 這樣, QTextEdit就會顯示gif動畫了

 

最后是添加gif圖片:

可以插入HTML: 

editor->append("<img src=\"TestImageTag\" />");

即img中指定為我們自定義的url即可

也可以使用QTextCursor插入:

QTextCursor cursor = editor->textCursor(); 
QTextImageFormat imageFormat;
imageFormat.setName("TestImageTag");
cursor.insertImage(imageFormat);

PS: 可以使用兩個數組來保存自定義的URL和QMOVIE, 以便管理資源釋放等問題

PS2: 在我的測試中, 即使調用了Qtextedit和QTextDocument的clear也無法釋放addResource圖片資源的內存.  只有把QTextEdit整個delete掉, 才會釋放所有圖片資源占據的內存.  這是個問題, 可能需要看源碼來解決. 不過如果圖片不多的話, 這個問題也可以忽略

 

3. 如何遍歷QTextEdit中的內容

  QTextEdit中的內容實際上是由QTextDocument維護

  可以簡單的理解: QTextDocument 包含 N個QTexBlock(段落), 每個QTexBlock包含N個QTextFragment

  

QColor _GetRamdomColor()
{
    QColor col; 
    int RamdomNum = rand() % 0xffffff; 
    char strCol[8];
    sprintf(strCol, "#%06x", RamdomNum);     
    col.setNamedColor(QString::fromLocal8Bit(strCol, 8)); 
    return col; 
}


void MyClass::OnTest()
{
    QTextDocument *document = ui.textEdit->document(); 
    QTextBlock &currentBlock = document->begin();
    QTextBlock::iterator it;
    QTextCursor cursor = ui.textEdit->textCursor(); 

    while( true)
    {
        // 在修改chatformat時會改變當前Block的fragment
        // 所以++it的處理類似std::map中的erase操作
        for (it = currentBlock.begin(); !(it.atEnd()); )
        {
            QTextFragment currentFragment = it.fragment();
            QTextImageFormat newImageFormat = currentFragment.charFormat().toImageFormat();

            if (newImageFormat.isValid()) {
                // 判斷出這個fragment為image
                ++it; 
                continue;
            }


            if (currentFragment.isValid())
            {
                ++it; 
                int pos = currentFragment.position();
                QString strText = currentFragment.text();
                for(int i = 0; i < strText.length(); i++)
                {    
                    // 選擇一個字, 隨機設定顏色
                    QTextCharFormat fmt;
                    fmt.setForeground(_GetRamdomColor());                    
                    QTextCursor helper = cursor;
                    helper.setPosition(pos++);
                    helper.setPosition(pos, QTextCursor::KeepAnchor);
                    helper.setCharFormat(fmt);
                }                
            }

        }

        currentBlock = currentBlock.next();
        if(!currentBlock.isValid())
            break;
    }
    // 光標移動到最后, 並設置擁有焦點
    QTextCursor c = ui.textEdit->textCursor();
    c.movePosition(QTextCursor::End, QTextCursor::MoveAnchor); 
    ui.textEdit->setTextCursor(c);    
    ui.textEdit->setFocus(Qt::MouseFocusReason);
}

這段代碼用於渲染QTextEdit為炫彩, 每個字隨機分配一種顏色

遍歷的時候, 判斷是圖片還是文字. 並作相應的處理

同時, 處理下QTextDocument的contentChange事件, 即可在鍵盤輸入時, 就改變字的顏色

    connect(document, SIGNAL(contentsChange( int , int , int )), 
        this, SLOT(OnContentChange( int , int , int )));
void MyClass::OnContentChange( int position, int charsRemoved, int charsAdded )
{
    if(charsAdded == 0)
        return;

    QTextCursor cursor = ui.textEdit->textCursor(); 
    for (int i = 0; i < charsAdded; i++ )
    {
        int pos = position + i; 
        // 選擇一個字, 隨機設定顏色
        QTextCharFormat fmt;
        fmt.setForeground(_GetRamdomColor());
        QTextCursor helper = cursor;
        helper.setPosition(pos);
        helper.setPosition(pos+1, QTextCursor::KeepAnchor);
        helper.setCharFormat(fmt);
    }

}

PS: 對某段文字執行setCharFormat也會觸發contentChange信號, 並且charsRemoved == charsAdded; 可以處理一下這個case

  這樣一般來說滿足了大部分需求, 做出類似QQ的聊天輸入框只需要再處理下復制黏貼圖片之類就行了. 至於Qt的rich edit中frame table list等, 需要的話, 就看看文檔吧, 感覺功能不是很必要


免責聲明!

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



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