[英]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();
}
我已經解決了。 我將QDocument
的contentsChange
信號與MessageBoard2
的textInserted
插槽連接起來。 每當插入任何文本時,我都會復制它們並將其從文檔中刪除,然后解析其 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.