目录
2.1 关于qt加入串口头文件#include <QSerialPort> #include <QSerialPortInfo>报错的问题,解决方案
三、串口下拉列表显示配置信息initComboBox_Config()
3.2 QT creator的ui界面和实际运行出来的界面不一致
四、点击刷新按钮函数刷新界面on_btnRefresh_clicked()
五、打开串口按钮配置on_btnOpenPort_clicked
七、接收文本框显示组件光标到尾部on_textBrower_textChanged()
八、监控输入文本on_txtSingle_textChanged()
九、发送按钮发送数据on_btnSend_clicked()
9.1 将QString转换为QByteArray(stringToSend)
9.2 发送信号signals_displayTxBuffer(txBuf)/slots_displayTxBuffer(QByteArray txBuffer)
10.2 启用定时器和停止定时器startTxTimer()/deleteTxTimer()
10.3 时间到了发送数据slots_timeOutTx()
10.4 按键勾选定时发送点击事件on_chbTimedTx_clicked(bool checked)
十一、修改定时发送的时间间隔on_spbTxInterval_editingFinished()
十二、保存接收的数据到文件on_btnSaveFile_clicked()
十三、发送行高亮显示 void slots_highlightLine()
工程下载链接:温度助手下载链接
一、添加图标和软件名称
图标下载网站,没有合适的就自己画一个
将png格式图标转成ico格式,网上有很多在线转换工具,经过试验发现48*48像素是最合适的
https://www.easyicon.net/covert/
在工程目录下创建res-general文件夹存放转换好的ico图标
1.1 修改QT程序
修改pro文件,添加以下内容
# 应用程序图标ico
RC_ICONS = res/general/tempcurve.ico
1.2 修改软件名称
在temperassistant.cpp中的
TemperAssistant::TemperAssistant(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::TemperAssistant)
{
ui->setupUi(this);
this->setWindowTitle("CETC-温度数据图像化工具 v1.0");
}
运行结果
二、串口建立
首先将两个串口程序文件baseserialcomm.cpp/baseserialcomm.h添加到工程文件夹中,
该文件都是包含相关串口设置的
添加完毕
在temperassistant.h中引入头文件
include "baseserialcomm.h" /*串口模块*/
点击运行会报错:如下图所示
2.1 关于qt加入串口头文件#include <QSerialPort> #include <QSerialPortInfo>报错的问题,解决方案
出现直接加入头文件报错的现象
需要在.pro文件下的QT+ =后面增加serialport
QT += serialport
在进行编译就不出错了。
三、串口下拉列表显示配置信息initComboBox_Config()
在temperassistant.h的TemperAssistant类下的public:创建一个串口初始化下拉列表函数
void initComboBox_Config(); // 初始化串口配置的下拉列表(ComboBox)
在temperassistant.c中写下该函数
/**
* @brief TemperAssistant::initComboBox_Config 初始化下拉列表控件
*/
void TemperAssistant::initComboBox_Config()
{
/* 更新下拉列表 */
BaseSerialComm::listBaudRate( ui -> cbbBaud );
BaseSerialComm::listDataBit ( ui -> cbbDataBit );
BaseSerialComm::listVerify ( ui -> cbbVerify );
BaseSerialComm::listStopBit ( ui -> cbbStopBit );
BaseSerialComm::listPortNum ( ui -> cbbPortNum );
}
该初始化函数,是引用baseserialcomm.h中 BaseSerialComm类下的几个函数
void BaseSerialComm::listStopBit(QComboBox *cbbStopBit)
void BaseSerialComm::listVerify(QComboBox *cbbVerify)
void BaseSerialComm::listDataBit(QComboBox *cbbDataBit)
void BaseSerialComm::listBaudRate(QComboBox *cbbBaud)
void BaseSerialComm::listPortNum(QComboBox *cbbPortNum)
并且将函数的输入形参设置为TemperAssistant UI 界面的控件名称(Ui::TemperAssistant *ui;)
即 ui -> cbbBaud
在初始化ui界面前同时初始化串口下拉列表参数配置函数
在temperassistant.c中的窗口构造函数中初始化它。
TemperAssistant::TemperAssistant(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::TemperAssistant)
{
ui->setupUi(this);
this->initComboBox_Config();
/* ui初始化 */
this->setWindowTitle("CETC-温度数据图像化工具 v1.0");
}
3.1 端口错误信息处理
前面引入的baseserialcomm.h和baseserialcomm.cpp中在baseserialcomm.h头文件中创建了一个串口类 BaseSerialComm
在temperassistant.h头文件中我们定义一个类指针的私有private:指针
BaseSerialComm *currentPort; // 端口号
这个指针是用 baseserialcomm.h里面的类定义的,所以指针*currentPort是指向baseserialcomm里面的内容,要访问baseserialcomm里面的内容都要用到指针。
在temperassistant.c中的窗口构造函数中创建一个端口对像
TemperAssistant::TemperAssistant(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::TemperAssistant)
{
ui->setupUi(this);
this->initComboBox_Config();
/* ui初始化 */
this->setWindowTitle("CETC-温度数据图像化工具 v1.0");
/* 功能配置 */
currentPort = new BaseSerialComm(); // 构建一个端口对象
}
在temperassistant.h的TemperAssistant类下的public slots:创建错误处理函数
void slots_errorHandler(QSerialPort::SerialPortError error);
在temperassistant.c中写下错误信息处理函数代码
/**
* @brief TemperAssistant::slots_errorHandler 错误信息处理
* @param error
*/
void TemperAssistant::slots_errorHandler(QSerialPort::SerialPortError error)
{
switch(error)
{
case QSerialPort::DeviceNotFoundError:QMessageBox::information(NULL, tr("未找到设备"), tr("检查设备是否已经连接,或者是否正常供电"), 0, 0);
break;
case QSerialPort::OpenError:
case QSerialPort::PermissionError:QMessageBox::information(NULL, tr("打开失败"), tr("检查设备是否已被其他软件占用"), 0, 0);
break;
default:break;
}
}
在temperassistant.c中的窗口构造函数中将错误处理函数与错误信号关联
TemperAssistant::TemperAssistant(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::TemperAssistant)
{
ui->setupUi(this);
this->initComboBox_Config();
/* ui初始化 */
this->setWindowTitle("CETC-温度数据图像化工具 v1.0");
/* 功能配置 */
currentPort = new BaseSerialComm(); // 构建一个端口对象
connect(currentPort,
SIGNAL(errorOccurred(QSerialPort::SerialPortError)),this,
SLOT(slots_errorHandler(QSerialPort::SerialPortError)) );//错误信号关联处理函数
}
void QSerialPort::errorOccurred(QSerialPort::SerialPortError error)当串行端口中发生错误时,会发出此信号。指定的错误描述发生的错误类型。
演示如下:
3.2 QT creator的ui界面和实际运行出来的界面不一致
在使用qt开发的时候,每次创建工程,都会默认选中shadow build影子构建,
作用是把编译生成的文件与源文件放在不同的目录,这样源码目录就相对整洁,但是这也会带来个问题,就是经常修改了代码之后点运行,跑的还是修改之前的程序。
这样的的话编译运行的相关项目文件就都在之前创立的项目文件里面了,看起来会凌乱一些。
如何默认不在勾选呢
去除默认选中shadow build方法:
选择工具----选项
../%{JS: Util.asciify("build-%{CurrentProject:Name}-%{CurrentKit:FileSystemName}-%{CurrentBuild:Name}")}
如下,修改为. ( 表示当前目录),然后选择ok,以后每次新建项目将不再默认选中影子构建
改完之后Apply就会发现默认地址就是在源文件下面呢。
四、点击刷新按钮函数刷新界面on_btnRefresh_clicked()
在temperassistant.h的TemperAssistant类下的private slots:创建一个串口端口刷新槽函数
private slots:
void on_btnRefresh_clicked();
在temperassistant.c中写下该函数
/**
* @brief TemperAssistant::on_btnRefresh_clicked 点击刷新按钮,刷新串口号
*/
void TemperAssistant::on_btnRefresh_clicked()
{
if( !ui->btnOpenPort->isChecked()){ // 关闭串口才能刷新端口号
ui -> cbbPortNum ->clear();
BaseSerialComm::listPortNum ( ui -> cbbPortNum );
}
}
五、打开串口按钮配置on_btnOpenPort_clicked
会自动生成该槽函数
在temperassistant.h的private slots:会自动添加
void on_btnOpenPort_clicked(bool checked);
在temperassistant.c中我们添加如下功能
功能如下:
/**
* @brief TemperAssistant::on_btnOpenPort_clicked 打开串口
* @param checked
*/
void TemperAssistant::on_btnOpenPort_clicked(bool checked)
{
QString tmp = ui->cbbPortNum->currentText(); //将端口号值赋给字符串变量tmp
tmp = tmp.split(" ").first();// Item的 text 由 <COM1 "描述"> 组成,使用空格作为分隔符取第一段就是端口名
if(checked)
{ //当前串口处于关闭状态
currentPort->setPortName(tmp);//设置串口号
if(currentPort->open(QIODevice::ReadWrite))// 打开串口
{
/* 配置端口的波特率等参数 */
this->configPort();
ui->btnOpenPort->setText("关闭串口");//打开串口按钮显示关闭串口
}
else
{
ui->btnOpenPort->setChecked(false);
}
}
else
{
currentPort->close();
ui->btnOpenPort->setText(tr("打开串口"));
}
}
六、设置端口波特率等参数函数configPort()
首先在temperassistant.h的public手动添加参数配置函数 configPort()
void configPort(); // 初始化配置串口
在temperassistant.c的 configPort()函数添加如下代码
/**
* @brief TemperAssistant::configPort配置端口的波特率\数据位\奇偶校验\停止位
*/
void TemperAssistant::configPort()
{
QVariant tmpVariant;
/* 设置波特率 */
tmpVariant = ui->cbbBaud->currentData(); // 读取控件的当前项的值
currentPort->setBaudRate(tmpVariant.value < BaseSerialComm::BaudRate > () );
/* 设置数据位 */
tmpVariant = ui->cbbDataBit->currentData();
currentPort->setDataBits( tmpVariant.value <BaseSerialComm::DataBits > () );
/* 设置校验位 */
tmpVariant = ui->cbbVerify->currentData();
currentPort->setParity (tmpVariant.value < BaseSerialComm::Parity > () );
/* 设置停止位 */
tmpVariant = ui->cbbStopBit->currentData();// 某些情况不支持1.5停止位
if(currentPort->setStopBits (tmpVariant.value < BaseSerialComm::StopBits > () ) == false ){
ui -> cbbStopBit->clear();
BaseSerialComm::listStopBit ( ui -> cbbStopBit );
QMessageBox::information(NULL, tr("不支持的设置"), tr("该串口设备不支持当前停止位设置,已修改为默认的设置"), 0, 0);
}
currentPort->setDataTerminalReady(false);
currentPort->setRequestToSend(false);
}
七、接收文本框显示组件光标到尾部on_textBrower_textChanged()
用Qt写一个串口调试工具,用一个QTextEdit作为接收显示区。发现每次串口调试工具接收完一帧数据后,QTextEdit的光标自动跳到文本开头的位置。这样,当接收到大量数据后,就要手动拉动滑块进行翻页,才能看到最新的数据。
首先在temperassistant.h的private slots:手动声明void on_textBrower_textChanged();
在temperassistant.c中写入代码。
/**
* @brief SerialAssistant::on_textBrower_textChanged 设置光标到尾部
*/
void SerialAssistant::on_textBrower_textChanged()
{
ui->textBrower->moveCursor(QTextCursor::End);
}
八、监控输入文本on_txtSingle_textChanged()
如果你点击了HEX输入则对输入文本进行监控
在temperassistant.h的private slot:自动生成
void on_txtSingle_textChanged();//监控输入文本
然后在temperassistant.c中输入代码
/**
* @brief SerialAssistant::on_txtSingle_textChanged 监控输入文本
*/
void TemperAssistant::on_txtSingle_textChanged()
{
if(ui->chbTxHex->isChecked() )//如果点击了HEX输入则进行如下判定
{
bool isMatch = BaseSerialComm::isHexString(ui->txtSingle->toPlainText());//检查输入文本中字符是否符合Hex规则表达式
if(!isMatch)//如果不符合HEX输入格式则进行字符串内容判断
{
QString tmp;
disconnect(this->ui->txtSingle,SIGNAL(textChanged()),this,SLOT(on_txtSingle_textChanged()));
tmp = ui->txtSingle->toPlainText();//转换为纯文本
tmp.replace(QRegExp("[^a-f0-9A-F ]"),"");
ui->txtSingle->setPlainText(tmp);
ui->txtSingle->moveCursor(QTextCursor::End);
QMessageBox::information(NULL, tr("不支持输入"), tr("只支持[0~9],[a~f],[A~F]和空格的输入"), 0, 0);
connect(this->ui->txtSingle,SIGNAL(textChanged()),this,SLOT(on_txtSingle_textChanged()));
}
}
}
然后在temperassistant.c初始化函数中输入代码
/* 监控输入的文本 */
disconnect(this->ui->txtSingle,SIGNAL(textChanged()),this,SLOT(on_txtSingle_textChanged()));
当你在输入文本框中输入除0-9/a-f/A-F的其他字符时会提示输入错误。
九、发送按钮发送数据on_btnSend_clicked()
首先在temperassistant.h的public slot:添加声明
void TemperAssistant::on_btnSend_clicked()
然后在temperassistant.c中输入代码
/**
* @brief TemperAssistant::on_btnSend_clicked 发送按钮
*/
void TemperAssistant::on_btnSend_clicked()
{
QByteArray txBuf;
if(currentPort->isOpen())//判定串口是否打开
{
bool ok ;//设定一个标志位
txBuf = this->stringToSend(ui->txtSingle->toPlainText(),ui->chbTxHex->isChecked(),ok);//引用将QString转换为QByteArray函数
if(false == ok)
{
if(txTimer.isActive())//如果定时器运行返回true否则返回false
{
this->deleteTxTimer();//停止定时并停止发送数据
ui->chbTimedTx->setCheckState(Qt::CheckState::Unchecked);//定时发送复选框按钮未选择
}
return;
}
/* 显示发送字节数 */
qint32 txBytes = currentPort->write(txBuf); // 发送数据
txCount += txBytes;
ui->lbltxCnt->setText(QString("%1").arg(txCount));
/* 显示发送数据 */
if( ui->checkBox_2->checkState() ){// 加时间戳
emit signals_displayTxBuffer(txBuf);
}
}
}
9.1 将QString转换为QByteArray(stringToSend)
首先在temperassistant.h的public:手动声明QByteArray stringToSend(QString src, bool txInHex, bool &ok );转化为16进制
该函数作用是将QString转换为QByteArray
QByteArray stringToSend(QString src, bool txInHex, bool &ok );
ui->txtSingle->toPlainText()意思是提取输入文本框中的字符转化为文本
ui->chbTxHex->isChecked()意思是是否点击了Hex发送按钮
然后在temperassistant.c中输入代码
/* 将QString 转换成可以直接发送的QByteArray */ // "33 35" -> 0x33 0x35
QByteArray TemperAssistant::stringToSend(QString src, bool txInHex, bool &ok )
{
QByteArray buf;
QString tmpString ;
ok = true;
if(txInHex){/* 以十六进制发送 */
tmpString = src.remove(QRegExp("\\s"));// delete ' '
QByteArray tmpTest = tmpString.toLatin1();// "33 35"->0x33 0x33 0x33 0x35
if(tmpTest.length() & 0x01 ) // 奇数个字符,最后一个字符不能满足转换成Hex数据
{
tmpTest.remove(tmpTest.length()-1, 1); // 移除并警告
QMessageBox::information(NULL, tr("不支持的输入"), tr("请输入完整的字节"), 0, 0);//输入字符串个数为奇数,窗口提示
ok = false;
}
buf = QByteArray::fromHex(tmpTest); // ascii to hex(hex字符串转换成 hex数据 )//0x33 0x33 0x33 0x35 -> 0x33 0x35
}else{
if( ui->rdbGB18030->isChecked() ){
QTextCodec *codec = QTextCodec::codecForName("GB18030");
buf = codec->fromUnicode(src);
}else{
buf = src.toUtf8();
}
}
return buf;
}
src.remove(QRegExp("\\s"));//QString去掉所有空格
1. qt 中两个字符的字符串直接转换为 hex,类似于 ”1A" 要转换成 16进制的 0x1A,使用 int QString::toInt(bool *ok, int base)。具体如下:
QString str = "0x1A"; int value = str.toInt(nullptr, 16); uint8_t tmp = static_cast<uint8_t>(str.toUInt(nullptr, 16));
2. 如果是字符串本身转换为16进制,类似于 "1" 要转换成 0x31,使用 QByteArray,其中有方法 toLatin1、toLocal8Bit, Latin1代表ASCII,Local8Bit代表unicode
QByteArray ar = str.toLatin1().toHex();
3. 如果是16进制转为 QByteArray,可以用 setNum 函数
QByteArray().setNum( hex )
9.2 发送信号signals_displayTxBuffer(txBuf)/slots_displayTxBuffer(QByteArray txBuffer)
首先在首先在temperassistant.h的signal:添加信号
void signals_displayTxBuffer(QByteArray);
在temperassistant.h的public slot:添加发射文本槽函数
void slots_displayTxBuffer(QByteArray);//发射文本槽函数
在启动函数下面将信号和槽函数关联起来
connect(this, SIGNAL( signals_displayTxBuffer(QByteArray )), this,SLOT(slots_displayTxBuffer(QByteArray)),Qt::QueuedConnection);
并在然后在temperassistant.c中输入slots_displayTxBuffer(QByteArray txBuffer)代码
/**
* @brief TemperAssistant::slots_displayTxBuffer 显示发送的数据帧
* @param txBuffer
*/
void TemperAssistant::slots_displayTxBuffer(QByteArray txBuffer)
{
/* 显示发送数据 */
// Hex显示
if(txBuffer.isEmpty())
return;
if( ui->chkDisplayHex->checkState() )//Hex显示勾选
{
txBuffer = txBuffer.toHex(' ').toUpper();//将数据转换成16进制大写
}
txBuffer.insert(0, QTime::currentTime().toString("[hh:mm:ss.zzz]Tx:"));
//在txBuffer数组的第0位插入时间戳
QString strToDisplay;//显示设置
if(ui->rdbGB18030->isChecked())
{
QTextCodec *codec = QTextCodec::codecForName("GB18030");//繁体编码
strToDisplay = codec->toUnicode( txBuffer );
}
else
{
strToDisplay = QString::fromUtf8(txBuffer);//标准编码
}
ui->textBrower->appendPlainText(strToDisplay);//另起一行
}
9.3 显示发送的字节数txCount
首先在temperassistant.h的public中定义发送字节数变量txCount
quint32 txCount = 0; // 发送字节计数
十.定时发送点击事件
10.1 发送用定时器txTimer
首先在temperassistant.h的public中声明发送文本需要的定时器
QTimer txTimer; // 发送用的定时器
10.2 启用定时器和停止定时器startTxTimer()/deleteTxTimer()
首先在temperassistant.h的public:添加声明
void deleteTxTimer(); // 停止发送定时器
void startTxTimer(); // 启动发送定时器
然后在temperassistant.c中输入代码
/**
* @brief TemperAssistant::startTxTimer 启动定时器,用于定时发送
*/
void TemperAssistant::startTxTimer()
{
txTimer.setTimerType(Qt::PreciseTimer );//设置定时器精度为毫秒级
qint32 tmp = ui->spbTxInterval->value();//读取时间栏里面的时间QSpinBox
txTimer.start(tmp);//启动定时器
connect(&txTimer,SIGNAL(timeout()),this,SLOT(slots_timeOutTx()));
}
/**
* @brief TemperAssistant::deleteTxTimer 停止定时发送
*/
void TemperAssistant::deleteTxTimer()
{
/* 停止定时器 */
if(txTimer.isActive())
{
txTimer.stop();
disconnect(&txTimer,SIGNAL(timeout()),this,SLOT(slots_timeOutTx()));
}
}
10.3 时间到了发送数据slots_timeOutTx()
在定义在temperassistant.h的public slot:添加声明
void slots_timeOutTx();//时间到了发送数据
然后在temperassistant.c中输入代码
/**
* @brief TemperAssistant::slots_timeOutTx 定时发送数据
*/
void TemperAssistant::slots_timeOutTx()
{
if(currentPort->isOpen())//如果串口打开返回true
{
emit this->ui->btnSend->click();// 发送单条数据,与点击"发送"按钮功能一致
}
}
时间到了如果串口开启则启动按键按下的程序也就是这个on_btnSend_clicked()
10.4 按键勾选定时发送点击事件on_chbTimedTx_clicked(bool checked)
在定义在temperassistant.h的private slot:自动添加声明
void on_chbTimedTx_clicked(bool checked);//自动发送复选框
在temperassistant.c中输入代码
/**
* @brief TemperAssistant::on_chbTimedTx_clicked 定时发送点击事件
* @param checked
*/
void TemperAssistant::on_chbTimedTx_clicked(bool checked)
{
if(checked)//判断如果勾选了
{
if(currentPort->isOpen() )//判断串口打开
{
this->startTxTimer();//开启定时发送
}
}
else if(txTimer.isActive())//如果计时器正在运行,则返回true;否则返回false。
{
this->deleteTxTimer();
}
}
十一、修改定时发送的时间间隔on_spbTxInterval_editingFinished()
在定义在temperassistant.h的private slot:自动添加声明
void on_spbTxInterval_editingFinished();//修改定时发送的时间间隔
在temperassistant.c中输入代码
/**
* @brief TemperAssistant::on_spbTxInterval_editingFinished 修改定时发送的时间间隔
*/
void TemperAssistant::on_spbTxInterval_editingFinished()
{
/* 改变定时器发送的 时间间隔 */
if(txTimer.isActive()){
qint32 tmp = ui->spbTxInterval->value();
txTimer.setInterval( tmp );
}
}
十二、保存接收的数据到文件on_btnSaveFile_clicked()
在定义在temperassistant.h的private slot:自动添加声明
void on_btnSaveFile_clicked();//保存接受的数据到文件
在定义在temperassistant.h的public:添加保存文件指针
QFile *saveFile;
QTextStream *txtStreamSave = NULL;//该类用于读写文本
在temperassistant.c中输入代码
/**
* @brief TemperAssistant::on_btnSaveFile_clicked 保存接收的数据到文件
*/
void TemperAssistant::on_btnSaveFile_clicked()
{
QString saveFilePath;//保存路径
QFileInfo fileInfo;
/* 获取文件绝对路径 */
if(ui->btnSaveFile->isChecked())//点击了保存文件按钮
{
saveFilePath.clear();//先将路径字符串清空
saveFilePath = QFileDialog::getSaveFileName(this, "Open File", NULL ,
"Files (*.txt *.log);;All (*.*)");//保存文件格式
if( NULL != saveFilePath)//如果保存路径为非空,即选择了保存路径
{
saveFile = new QFile(saveFilePath);
saveFile->open(QIODevice::WriteOnly | QIODevice::WriteOnly);
txtStreamSave = new QTextStream(saveFile);
fileInfo = saveFilePath;//保存路径
ui->btnSaveFile->setText(fileInfo.fileName());//保存至文件按钮显示文件名称
ui->textBrower->appendPlainText(QString("新接收到的数据将会被保存到 %1 ,以下内容就是文件保存内容").arg(saveFilePath));//文本框中显示
}
else
{
ui->btnSaveFile->setChecked(false);
}
}
else if( NULL != saveFile)//如果保存文件为非空,即保存了文件
{
saveFile->close();//关闭保存文件
delete saveFile;//删除保存的对象
delete txtStreamSave;
saveFile = NULL;
txtStreamSave = NULL;
ui->btnSaveFile->setText("保存至文件");//保存文件按钮依旧显示保存至文件
}
}
在temperassistant.c初始化函数中初始化文件对象
saveFile = NULL; // 保存文件指针
十三、发送行高亮显示 void slots_highlightLine()
在定义在temperassistant.h的pubic slot:手动添加声明
void slots_highlightLine();//发射文本框光标所在行高亮显示
在temperassistant.c中添加高亮槽函数代码
/**
* @brief TemperAssistant::slots_highlightLine 发送文本框的光标位置改变 光标所在行高亮
*/
void TemperAssistant::slots_highlightLine()
{
QList<QTextEdit::ExtraSelection> extraSelections;//提供一种方式显示选择的文本
QTextEdit::ExtraSelection selection;
selection.format.setBackground(QColor(223, 134, 30).lighter(60)); // 设置背景颜色和亮度
selection.format.setProperty(QTextFormat::FullWidthSelection, true); // 选择当前行所有像素(宽)
selection.cursor = ui->txtSingle->textCursor(); // 高亮当前行
extraSelections.append(selection);
ui->txtSingle->setExtraSelections(extraSelections); //设置高亮
}
在temperassistant.c初始化函数中链接高亮显示 信号->槽
connect(this->ui->txtSingle,SIGNAL(cursorPositionChanged()),this,SLOT(slots_highlightLine())); // 链接高亮显示 信号->槽