[英]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.