效果如下:
如何对QTextEditor中的内容进行高亮和格式化显示:
- 首先我们要自定义一个类WenshiduHighlighter,继承自QSyntaxHighlighter
- 实现构造函数,在构造函数中将需要匹配的正则和对应的格式创建,存到成员变量中
- 重写父类的void highlightBlock(const QString &text) = 0函数,在该函数中对text利用之前创建的正则进行匹配,若匹配上了,则调用父类的setFormat方法将对应的格式设置进去
代码如下:
cpp
//自定义一个高亮类,需要继承自抽象类QSyntaxHighlighter
class WenshiduHighlighter:public QSyntaxHighlighter
{
Q_OBJECT
public:
//定义高亮规则结构体
struct HighlightRule
{
//需要匹配的正则(通过正则来找到你要想高亮的那一部分字符)
QRegularExpression pattern;
//正则匹配到的字符串对应的格式
QTextCharFormat format;
};
//实现构造函数,参数就是QTextEditor里面的内容,QTextDocument;
//该参数主要是为了用来初始化父类QSyntaxHighlighter
WenshiduHighlighter(QTextDocument* doc):QSyntaxHighlighter(doc)
{
//在构造函数中,初始化highlight_rules,创建想要高亮的内容和对应的格式
HighlightRule rule;
//下面就属于正则表达式的内容了 ,正则怎么写不赘述
//日期,在一对[]内
rule.pattern=QRegularExpression(R"(\[.*\])");
QTextCharFormat datetime_format;
datetime_format.setForeground(QColor(85,85,85));//设置前景色
datetime_format.setBackground(QColor(240,240,240));//设置背景色
datetime_format.setFontWeight(QFont::Bold);//设置加粗
datetime_format.setFontFamily("Consolas");
rule.format=datetime_format;
highlight_rules.push_back(rule);
//温度key
rule.pattern=QRegularExpression(R"(Temperature)");
QTextCharFormat temper_key_format;
temper_key_format.setForeground(QColor(180,30,110));
temper_key_format.setFontFamily("Consolas");
rule.format=temper_key_format;
highlight_rules.push_back(rule);
//温度value
rule.pattern=QRegularExpression(R"((?<=Temperature:)\s*-*\d+℃)");//反向预查,以Temperature:开始
QTextCharFormat temper_val_format;
temper_val_format.setForeground(QColor(180,30,110));
temper_val_format.setFontWeight(QFont::Bold);
temper_val_format.setFontFamily("Consolas");
rule.format=temper_val_format;
highlight_rules.push_back(rule);
//湿度key
rule.pattern=QRegularExpression(R"(Humidity)");
QTextCharFormat humi_key_format;
humi_key_format.setForeground(QColor(97,54,134));
humi_key_format.setFontFamily("Consolas");
rule.format=humi_key_format;
highlight_rules.push_back(rule);
//湿度value
rule.pattern=QRegularExpression(R"((?<=Humidity:)\s*\d+%)");//反向预查
QTextCharFormat humi_val_format;
humi_val_format.setForeground(QColor(97,54,134));
humi_val_format.setFontWeight(QFont::Bold);
humi_val_format.setFontFamily("Consolas");
rule.format=humi_val_format;
highlight_rules.push_back(rule);
//正常
rule.pattern=QRegularExpression(R"(\(Normal\))");
QTextCharFormat normal_format;
normal_format.setForeground(Qt::darkGreen);
normal_format.setFontFamily("Consolas");
rule.format=normal_format;
highlight_rules.push_back(rule);
//偏低
rule.pattern=QRegularExpression(R"(\(↓Lower\))");
QTextCharFormat lower_format;
lower_format.setForeground(Qt::white);
lower_format.setBackground(Qt::darkBlue);
lower_format.setFontWeight(QFont::Bold);
lower_format.setFontFamily("Consolas");
rule.format=lower_format;
highlight_rules.push_back(rule);
//偏高
rule.pattern=QRegularExpression(R"(\(↑Upper\))");
QTextCharFormat upper_format;
upper_format.setForeground(Qt::white);
upper_format.setBackground(QColor(220,50,50));
upper_format.setFontWeight(QFont::Bold);
upper_format.setFontFamily("Consolas");
rule.format=upper_format;
highlight_rules.push_back(rule);
}
~WenshiduHighlighter()=default;
protected:
//最后,我们要重写父类的抽象接口void highlightBlock(const QString &text) = 0
//这个函数的参数text,就是构造传进来的doc的每一行,
//该父类会自动把doc的每一行都来调用这个函数来进行匹配+高亮
void highlightBlock(const QString &text) override
{
//遍历所有的规则,来给每一行的数据匹配后设置格式
for(const auto& itor:highlight_rules)
{
auto match_list=itor.pattern.globalMatch(text);
//如果匹配到了
while(match_list.hasNext())
{
auto match_result=match_list.next();
//最后调用父类的setFormat方法设置格式
//参数1:匹配到字符的开始索引
//参数2:匹配到字符的长度
//参数3:预先构造好的格式
setFormat(match_result.capturedStart(),
match_result.capturedLength(),
itor.format);
}
}
}
private:
std::vector<HighlightRule> highlight_rules;
};
如何使用
- 设置高亮,直接new一个WenshiduHighlighter,然后将QTextEditor内部文档的指针传过来
- 取消高亮,直接delete掉前面new出来的WenshiduHighlighter
代码如下:
cpp
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr):QWidget(parent)
{
setStyleSheet(R"(QPushButton{
font-family:"Microsoft YaHei";
font-size:13px;
font-weight:bold;
}
QCheckBox{
font-family:"Microsoft YaHei";
font-size:13px;
font-weight:bold;
})");
//整个窗口垂直布局
QVBoxLayout* v_box=new QVBoxLayout(this);
//创建复选框和两个按钮,三者采用水平布局
QHBoxLayout* h_box=new QHBoxLayout();
format_box=new QCheckBox(this);
format_box->setText("下位机温湿度高亮");
h_box->addWidget(format_box);
QSpacerItem* spacer1=new QSpacerItem(20,5,QSizePolicy::MinimumExpanding,QSizePolicy::Fixed);
h_box->addSpacerItem(spacer1);
btn_start_receive=new QPushButton(this);
btn_start_receive->setText("开始接收");
btn_start_receive->setFixedSize(80,30);
btn_start_receive->setCursor(Qt::PointingHandCursor);
h_box->addWidget(btn_start_receive);
QSpacerItem* spacer2=new QSpacerItem(20,5,QSizePolicy::Fixed,QSizePolicy::Fixed);
h_box->addSpacerItem(spacer2);
btn_clear=new QPushButton(this);
btn_clear->setText("清除数据");
btn_clear->setFixedSize(80,30);
btn_clear->setCursor(Qt::PointingHandCursor);
h_box->addWidget(btn_clear);
v_box->addLayout(h_box);
//创建内容区
edit_content=new QTextEdit(this);
//设置为等宽字体,来使上下两行的数据对齐
edit_content->setStyleSheet("font:16px Courier");
v_box->addWidget(edit_content);
resize(800,600);
timer=new QTimer(this);
//开始接收按钮
//则开始一个定时器,以500ms为间隔模拟生成一条温湿度数据,追加到editor中
connect(btn_start_receive,&QPushButton::clicked,this,[=](){
//定时器开着,则关闭定时器,停止追加数据
if(timer->isActive())
{
timer->stop();
btn_start_receive->setText("开始接收");
}
else
{
//定时器关着,则开启定时器
timer->start(500);
btn_start_receive->setText("停止接收");
}
});
//清除按钮
connect(btn_clear,&QPushButton::clicked,this,[=](){
//清除数据
edit_content->clear();
});
//高亮下位机温湿度
connect(format_box,&QCheckBox::clicked,this,[=](){
if(format_box->isChecked())
{
//如何产生高亮,直接new一个温湿度高亮者,就可以高亮了
wenshidu_highlighter=new WenshiduHighlighter(edit_content->document());
}
else
{
//如何取消高亮。直接delete将他析构好了
delete wenshidu_highlighter;
}
});
//定时器
connect(timer,&QTimer::timeout,this,&Widget::addData);
}
~Widget()=default;
protected:
void addData()
{
QString str_data;
str_data+="[";
//日期时间
str_data+=QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss");
str_data+="] ";
//随机生成温度,范围【-10,50】
int temper=-10+QRandomGenerator::global()->generate()%61;
if(temper<10)
{
//arg(temper,3)表示温度占3位
str_data+=QString("%1%2%3").arg("Temperature: ").arg(temper,3).arg("℃ (↓Lower) ");
}
else if(temper>=10&& temper<30)
{
str_data+=QString("%1%2%3").arg("Temperature: ").arg(temper,3).arg("℃ (Normal) ");
}
else
{
str_data+=QString("%1%2%3").arg("Temperature: ").arg(temper,3).arg("℃ (↑Upper) ");
}
//随机生成湿度,范围【20,100】
int humi=20+QRandomGenerator::global()->generate()%81;
if(humi<40)
{
str_data+=QString("%1%2%3").arg("Humidity: ").arg(humi,3).arg("% (↓Lower)");
}
else if(humi>=40 && humi<70)
{
str_data+=QString("%1%2%3").arg("Humidity: ").arg(humi,3).arg("% (Normal)");
}
else
{
str_data+=QString("%1%2%3").arg("Humidity: ").arg(humi,3).arg("% (↑Upper)");
}
edit_content->append(str_data);
}
private:
QTimer* timer;
QCheckBox* format_box;//高亮内容
QPushButton* btn_start_receive;//接收数据
QPushButton* btn_clear;//清除内容
QTextEdit* edit_content;//内容区
WenshiduHighlighter* wenshidu_highlighter;
};