簡體   English   中英

在 QTextBrowser 中跟蹤文本插入

[英]Track text insertion in QTextBrowser

我正在制作一個應用程序並使用QTextBrowser來顯示消息。 它應該解析 ascii 顏色,所以我的類( say MessageBoard )是從QTextBrowser繼承的。 我可以在插入之前替換 ascii 顏色代碼並根據 ascii 代碼設置MessageBoard的文本顏色。

但是有很多方法可以將文本插入到QTextBrowser因此MessageBoard應該能夠准確檢測文本插入的位置及其長度

問題是, QTextBrowser (通過QTextEdit )僅提供 textChanged 信號,但無法獲取發生更改的位置。

那么有沒有辦法得到它或者我錯過了什么?

我已經解決了這個問題,但這是我遇到的問題(參見 main.cpp)。 留言板.h

#ifndef MESSAGEBOARD_H
#define MESSAGEBOARD_H

#include <QTextBrowser>

#define AC_BLACK        "\u001b[30m"
#define AC_RED          "\u001b[31m"
#define AC_GREEN        "\u001b[32m"
#define AC_YELLOW       "\u001b[33m"
#define AC_BLUE         "\u001b[34m"
#define AC_MAGENTA      "\u001b[35m"
#define AC_CYAN         "\u001b[36m"
#define AC_WHITE        "\u001b[37m"
#define AC_RESET        "\u001b[0m"

using AsciiStringPos = std::pair<int /*index*/,int /*length*/>;

class MessageBoard : public QTextBrowser
{
public:
    MessageBoard(QWidget *parent = nullptr);
    void appendText(const QByteArray &text);
    ~MessageBoard();
private:
    std::pair<AsciiStringPos,QColor> find_ascii(const QByteArray &text, int starts_from);
private:
    std::map<QByteArray, QColor> m_colors;
};
#endif // MESSAGEBOARD_H

留言板.cpp

#include "MessageBoard.h"
#include <QRegularExpression>
#include <climits>

MessageBoard::MessageBoard(QWidget *parent)
    : QTextBrowser(parent),
      m_colors({
{QByteArray(AC_BLACK) ,     Qt::black},
{QByteArray(AC_RED) ,       Qt::red},
{QByteArray(AC_GREEN) ,     Qt::green},
{QByteArray(AC_YELLOW) ,    Qt::yellow},
{QByteArray(AC_BLUE) ,      Qt::blue},
{QByteArray(AC_MAGENTA) ,   Qt::magenta},
{QByteArray(AC_CYAN) ,      Qt::cyan},
{QByteArray(AC_WHITE) ,     Qt::white}
               })
{
    m_colors.insert({QByteArray(AC_RESET) , textColor()});
}

void MessageBoard::appendText(const QByteArray &text)
{
    int index = 0;
    QTextCursor text_cursor = textCursor();
    text_cursor.movePosition(QTextCursor::End);
    auto res = find_ascii(text,0);
    while(res.first.first != -1)        //color string's index
    {
        text_cursor.insertText(text.mid(index,res.first.first - index));//append text before the color
        QTextCharFormat format;
        format.setForeground(res.second);   //set color to charformat
        text_cursor.setCharFormat(format);  //set charformat
        index = res.first.first         //color string started from
                + res.first.second;     //color string length
        res = find_ascii(text,index);   //find next color
    }
    text_cursor.insertText(text.mid(index));
}

std::pair<AsciiStringPos, QColor> MessageBoard::find_ascii(const QByteArray &text, int starts_from)
{
    QByteArray first_color;
    int min_index = INT_MAX;
    for(const auto &p : m_colors)
    {
        int index = text.indexOf(p.first,starts_from);
        if(index != -1 && min_index > index)
        {
            min_index = index;
            first_color = p.first;
        }
    }
    if(first_color.isNull())
        return {{-1,0},m_colors[QByteArray(AC_RESET)]};
    else
        return {{min_index,first_color.length()},m_colors[first_color]};
}

MessageBoard::~MessageBoard()
{
}

主程序

#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MessageBoard w;
    //appendText is manually created, so I can parse text before inserting.
    w.appendText(AC_GREEN "This is written with " AC_RED " Ascii " AC_GREEN " escaped words." AC_RESET);
    //append, can't do the same because I don't know the location where it was inserted.
    w.append(AC_MAGENTA "This won't be written in magenta.");
    w.appendText(AC_CYAN "This will be written in cyan" AC_RESET);
    w.zoomIn(5);
    w.show();
    return a.exec();
}

輸出圖像

我已經解決了。 我將QDocumentcontentsChange信號與MessageBoard2textInserted插槽連接起來。 每當插入任何文本時,我都會復制它們並將其從文檔中刪除,然后解析其 ascii 顏色代碼並根據代碼設置顏色。 然后我插入文本,更改文本顏色,插入文本,我通過循環遞歸地進行。 這是我的代碼

MessageBoard2.h #ifndef MESSAGEBOARD2_H #define MESSAGEBOARD2_H

#include <QTextBrowser>

#define AC_BLACK        "\u001b[30m"
#define AC_RED          "\u001b[31m"
#define AC_GREEN        "\u001b[32m"
#define AC_YELLOW       "\u001b[33m"
#define AC_BLUE         "\u001b[34m"
#define AC_MAGENTA      "\u001b[35m"
#define AC_CYAN         "\u001b[36m"
#define AC_WHITE        "\u001b[37m"
#define AC_RESET        "\u001b[0m"

class MessageBoard2 : public QTextBrowser
{
private:
    class SearchResults{
    private:
        struct result_t{
            std::size_t index;
            std::size_t length;
            QColor color;
        };
        std::vector<result_t> vec;
        std::size_t iterator;
    public:
        SearchResults() : iterator(0){}
        bool hasMatch() const {return !vec.empty();}
        bool hasNext() const {return iterator < vec.size();}
        const result_t &next() {return vec[iterator++];}
        friend class ::MessageBoard2;
    };
public:
    MessageBoard2(QWidget *parent = nullptr);
    ~MessageBoard2();
    SearchResults find_ascii(const QString &text, int starts_from);
private slots:
    void textInserted(int pos, int sub, int add);
    void parseAndInsert(const QString &text);
private:
    bool m_should_react;    //prevent recursive calls
    QTextDocument *m_document;
    std::map<QString, QColor> m_colors;
};

#endif // MESSAGEBOARD2_H

留言板2.cpp

#include "MessageBoard2.h"
#include <QRegularExpressionMatch>
#include <QTextBlock>

MessageBoard2::MessageBoard2(QWidget *parent) :
    QTextBrowser(parent),
    m_colors({
    {QStringLiteral(AC_BLACK) ,     Qt::black},
    {QStringLiteral(AC_RED) ,       Qt::red},
    {QStringLiteral(AC_GREEN) ,     Qt::green},
    {QStringLiteral(AC_YELLOW) ,    Qt::yellow},
    {QStringLiteral(AC_BLUE) ,      Qt::blue},
    {QStringLiteral(AC_MAGENTA) ,   Qt::magenta},
    {QStringLiteral(AC_CYAN) ,      Qt::cyan},
    {QStringLiteral(AC_WHITE) ,     Qt::white}
           }),
    m_should_react(true)
{
    m_colors.insert({QStringLiteral(AC_RESET),textColor()});
    m_document = document();
    connect(m_document,&QTextDocument::contentsChange,this,&MessageBoard2::textInserted);
}

MessageBoard2::~MessageBoard2()
{

}

void MessageBoard2::textInserted(int pos, int sub, int add)
{
    if(m_should_react && add > 0)
    {
        QTextCursor text_cursor = textCursor();
        text_cursor.setPosition(pos);
        text_cursor.setPosition(pos+add,QTextCursor::KeepAnchor);
        QString text = text_cursor.selectedText();
        m_should_react = false;
        text_cursor.removeSelectedText();
        setTextCursor(text_cursor);
        parseAndInsert(text);
        m_should_react = true;
    }
}

void MessageBoard2::parseAndInsert(const QString &text)
{
    int index = 0;
    QTextCursor text_cursor = textCursor();
    text_cursor.movePosition(QTextCursor::End);
    SearchResults results = find_ascii(text,0);
    while(results.hasNext())        //color string's index
    {
        const SearchResults::result_t &result = results.next();
        text_cursor.insertText(text.mid(index,result.index - index));//append text before the color
        QTextCharFormat format;
        format.setForeground(result.color);
        text_cursor.setCharFormat(format);
        index = result.index         //color string started from
                + result.length;     //color string length
    }
    text_cursor.insertText(text.mid(index));
}

MessageBoard2::SearchResults MessageBoard2::find_ascii(const QString &text, int starts_from)
{
    QRegularExpressionMatchIterator itr = QRegularExpression("\u001b\\[\\d+m").globalMatch(text);
    SearchResults results;
    while(itr.hasNext())
    {
        QRegularExpressionMatch match = itr.next();
        auto it = m_colors.find(match.captured());
        if(it != m_colors.end())
        {
            SearchResults::result_t result;
            result.index = match.capturedStart();
            result.length = match.capturedLength();
            result.color = it->second;
            results.vec.push_back(result);
        }
        std::cout << std::endl;
    }
    return results;
}

主程序

#include "MessageBoard2.h"

#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MessageBoard2 w;
    //execpt setPlainText function, I can parse the strings and set color accordingly.
    w.textCursor().insertText(AC_GREEN "This is written with " AC_RED " Ascii " AC_GREEN " escaped words." AC_RESET);
    w.insertPlainText(AC_MAGENTA "This will be written in magenta.");
    w.append(AC_CYAN "This will be written in cyan" AC_RESET);
    w.zoomIn(5);
    w.show();
    return a.exec();
}

輸出圖像

如果我很好地理解您的要求,我想您可能想使用此信號https://doc.qt.io/qt-5/qtextdocument.html#contentsChange

您將可以使用此https://doc.qt.io/qt-5/qtextedit.html#document-prop訪問QTextDocument

我希望當我們收到信號“textChanged”時,可以使用“ toplainText() ”函數來獲取文本。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM