I am making an application and using QTextBrowser
to show messages. It should parse ascii colors, so my class (say MessageBoard
) is inheriting from QTextBrowser
. I can replace ascii color code and set MessageBoard
's text color according to the ascii code before insertion.
But there are many ways of inserting text into the QTextBrowser
, so MessageBoard
should be able to detect exactly where text is inserted and what is its length.
The problem is, QTextBrowser
(through QTextEdit
) provides only textChanged signal but there is no way to get where changes happened.
So is there no way to get it or I missing something?
I've solved the problem but this was the issue I was having, (See main.cpp). MessageBoard.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
MessageBoard.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()
{
}
main.cpp
#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();
}
If I understand your request well, I guess you may want to use this signal https://doc.qt.io/qt-5/qtextdocument.html#contentsChange
You will get access to QTextDocument
with this https://doc.qt.io/qt-5/qtextedit.html#document-prop