QT串口调试助手
- 1.概述
- 2.界面设计
- 3.开发
- 3.1 串口调试助手自动检测串口
- 3.2 串口调试助手打开串口(配置串口参数)
- 3.3 对发送状态界面进行优化
- 3.4 串口调试助手实现自发自收功能
- 3.5 串口调试助手实现自动发送功能(QTimer)
- 3.6 串口调试助手保存清空接收按键
- 3.7 获取当前系统时间(QDateTime)
- 3.8 接收时间并显示
- 3.9 HEX显示(QByteArray)(to编码,from解码)
- 3.10 串口调试助手,发送HEX发送
- 3.11 串口调试助手添加换行功能
- 3.12 隐藏和显示
- 3.13 自定义ComboBox完成串口号列表的刷新
- 3.14 通过子控件组控制子控件(相同类型)(通过设置属性传参)
- 3.15 定时器循环发送
- 3.16 重置按键对话框定制
- 3.17 保存
- 3.18 载入
- 4. 打包
- 5. 总结-代码整合
1.概述
完成串口助手相应功能
2.界面设计
3.开发
3.1 串口调试助手自动检测串口
在头文件中添加: #include <QSerialPortInfo>
在.pro中添加: QT += serialport
//[static] QList<QSerialPortInfo> QSerialPortInfo::availablePorts()
QList<QSerialPortInfo> serialList = QSerialPortInfo::availablePorts(); //获取可用的串口列表
for(QSerialPortInfo serialinfo : serialList){ //迭代器迭代遍历
qDebug() << serialinfo.portName();
ui->comboBox_serialNum->addItem(serialinfo.portName()); //将可用的串口添加到串口中
3.2 串口调试助手打开串口(配置串口参数)
在头文件中添加: #include <QSerialPortInfo>
在.pro中添加: QT += serialport
/*
* --首先实例化串口对象而后配置串口参数
1.选择端口号
2.配置波特率
3.配置数据位
4.配置校验位
5.配置停止位
6.流控
*/
/*
enum Parity {
NoParity = 0,
EvenParity = 2,
OddParity = 3,
SpaceParity = 4,
MarkParity = 5,
UnknownParity = -1
};
*/
void Widget::on_btnCloseOrOpen_clicked()
{
if(!serialStatus){ //打开时
//1.选择端口号
serialPort->setPortName(ui->comboBox_serialNum->currentText());
//2.配置波特率
serialPort->setBaudRate(ui->comboBox_boautrate->currentText().toInt());
//3.配置数据位
serialPort->setDataBits(QSerialPort::DataBits(
ui->comboBox_databit->currentText().toUInt()));
//4.配置校验位
switch (ui->comboBox_jiaoyan->currentIndex()) {
case 0:
serialPort->setParity(QSerialPort::NoParity);
break;
case 1:
serialPort->setParity(QSerialPort::EvenParity);
break;
case 2:
serialPort->setParity(QSerialPort::MarkParity);
break;
case 3:
serialPort->setParity(QSerialPort::OddParity);
break;
case 4:
serialPort->setParity(QSerialPort::SpaceParity);
break;
default:
serialPort->setParity(QSerialPort::UnknownParity);
break;
}
//5.配置停止位
serialPort->setStopBits(QSerialPort::StopBits(
ui->comboBox_stopbit->currentText().toUInt()));
//6.配置流控
if(ui->comboBox_fileCon->currentText() == "None"){
serialPort->setFlowControl(QSerialPort::NoFlowControl);
}
//7.打开串口
if(serialPort->open(QIODevice::ReadWrite)){ //打开状态
qDebug() << "serial open success";
ui->comboBox_databit->setEnabled(false); //使其失效
ui->comboBox_fileCon->setEnabled(false); //使其失效
ui->comboBox_jiaoyan->setEnabled(false); //使其失效
ui->comboBox_stopbit->setEnabled(false); //使其失效
ui->comboBox_boautrate->setEnabled(false); //使其失效
ui->comboBox_serialNum->setEnabled(false); //使其失效
ui->btnCloseOrOpen->setText(QString("关闭串口"));
ui->btnSendContext->setEnabled(true);
serialStatus = true;
}else{ //打开失败
QMessageBox msgBox;
msgBox.setWindowTitle("打开串口错误");
msgBox.setText("打开失败,串口可能被占用.");
msgBox.exec();
}
}else{ //关闭时
serialPort->close();
ui->btnCloseOrOpen->setText("打开串口");
ui->comboBox_databit->setEnabled(true); //使其失效
ui->comboBox_fileCon->setEnabled(true); //使其失效
ui->comboBox_jiaoyan->setEnabled(true); //使其失效
ui->comboBox_stopbit->setEnabled(true); //使其失效
ui->comboBox_boautrate->setEnabled(true); //使其失效
ui->comboBox_serialNum->setEnabled(true); //使其失效
ui->btnSendContext->setEnabled(false);
serialStatus = false;
}
}
3.3 对发送状态界面进行优化
1.未打开时数据可设置,字符为打开串口
2.打开后数据不可设置,字符变为关闭串口
3.串口打开失败时有窗口提示
3.3.1 Checkable
//checkable默认为false 点击一下为true 再点为false
void Widget::on_btnCloseOrOpen_clicked(bool checked)
{
if(checked){ //打开时
//1.选择端口号
serialPort->setPortName(ui->comboBox_serialNum->currentText());
//2.配置波特率
serialPort->setBaudRate(ui->comboBox_boautrate->currentText().toInt());
//3.配置数据位
serialPort->setDataBits(QSerialPort::DataBits(
ui->comboBox_databit->currentText().toUInt()));
//4.配置校验位
switch (ui->comboBox_jiaoyan->currentIndex()) {
case 0:
serialPort->setParity(QSerialPort::NoParity);
break;
case 1:
serialPort->setParity(QSerialPort::EvenParity);
break;
case 2:
serialPort->setParity(QSerialPort::MarkParity);
break;
case 3:
serialPort->setParity(QSerialPort::OddParity);
break;
case 4:
serialPort->setParity(QSerialPort::SpaceParity);
break;
default:
serialPort->setParity(QSerialPort::UnknownParity);
break;
}
//5.配置停止位
serialPort->setStopBits(QSerialPort::StopBits(
ui->comboBox_stopbit->currentText().toUInt()));
//6.配置流控
if(ui->comboBox_fileCon->currentText() == "None"){
serialPort->setFlowControl(QSerialPort::NoFlowControl);
}
//7.打开串口
if(serialPort->open(QIODevice::ReadWrite)){ //打开状态
qDebug() << "serial open success";
ui->comboBox_databit->setEnabled(false); //使其失效
ui->comboBox_fileCon->setEnabled(false); //使其失效
ui->comboBox_jiaoyan->setEnabled(false); //使其失效
ui->comboBox_stopbit->setEnabled(false); //使其失效
ui->comboBox_boautrate->setEnabled(false); //使其失效
ui->comboBox_serialNum->setEnabled(false); //使其失效
ui->btnCloseOrOpen->setText(QString("关闭串口"));
ui->btnSendContext->setEnabled(true);
// serialStatus = true;
}else{ //打开失败
QMessageBox msgBox;
msgBox.setWindowTitle("打开串口错误");
msgBox.setText("打开失败,串口可能被占用.");
msgBox.exec();
}
}else{ //关闭时
serialPort->close();
ui->btnCloseOrOpen->setText("打开串口");
ui->comboBox_databit->setEnabled(true); //使其失效
ui->comboBox_fileCon->setEnabled(true); //使其失效
ui->comboBox_jiaoyan->setEnabled(true); //使其失效
ui->comboBox_stopbit->setEnabled(true); //使其失效
ui->comboBox_boautrate->setEnabled(true); //使其失效
ui->comboBox_serialNum->setEnabled(true); //使其失效
ui->btnSendContext->setEnabled(false);
// serialStatus = false;
}
}
3.3.2 设置状态标志位
void Widget::on_btnCloseOrOpen_clicked()
{
if(!serialStatus){ //打开时
//1.选择端口号
serialPort->setPortName(ui->comboBox_serialNum->currentText());
//2.配置波特率
serialPort->setBaudRate(ui->comboBox_boautrate->currentText().toInt());
//3.配置数据位
serialPort->setDataBits(QSerialPort::DataBits(
ui->comboBox_databit->currentText().toUInt()));
//4.配置校验位
switch (ui->comboBox_jiaoyan->currentIndex()) {
case 0:
serialPort->setParity(QSerialPort::NoParity);
break;
case 1:
serialPort->setParity(QSerialPort::EvenParity);
break;
case 2:
serialPort->setParity(QSerialPort::MarkParity);
break;
case 3:
serialPort->setParity(QSerialPort::OddParity);
break;
case 4:
serialPort->setParity(QSerialPort::SpaceParity);
break;
default:
serialPort->setParity(QSerialPort::UnknownParity);
break;
}
//5.配置停止位
serialPort->setStopBits(QSerialPort::StopBits(
ui->comboBox_stopbit->currentText().toUInt()));
//6.配置流控
if(ui->comboBox_fileCon->currentText() == "None"){
serialPort->setFlowControl(QSerialPort::NoFlowControl);
}
//7.打开串口
if(serialPort->open(QIODevice::ReadWrite)){ //打开状态
qDebug() << "serial open success";
ui->comboBox_databit->setEnabled(false); //使其失效
ui->comboBox_fileCon->setEnabled(false); //使其失效
ui->comboBox_jiaoyan->setEnabled(false); //使其失效
ui->comboBox_stopbit->setEnabled(false); //使其失效
ui->comboBox_boautrate->setEnabled(false); //使其失效
ui->comboBox_serialNum->setEnabled(false); //使其失效
ui->btnCloseOrOpen->setText(QString("关闭串口"));
ui->btnSendContext->setEnabled(true);
serialStatus = true;
}else{ //打开失败
QMessageBox msgBox;
msgBox.setWindowTitle("打开串口错误");
msgBox.setText("打开失败,串口可能被占用.");
msgBox.exec();
}
}else{ //关闭时
serialPort->close();
ui->btnCloseOrOpen->setText("打开串口");
ui->comboBox_databit->setEnabled(true); //使其失效
ui->comboBox_fileCon->setEnabled(true); //使其失效
ui->comboBox_jiaoyan->setEnabled(true); //使其失效
ui->comboBox_stopbit->setEnabled(true); //使其失效
ui->comboBox_boautrate->setEnabled(true); //使其失效
ui->comboBox_serialNum->setEnabled(true); //使其失效
ui->btnSendContext->setEnabled(false);
serialStatus = false;
}
}
3.4 串口调试助手实现自发自收功能
发送:通过发送控件转到槽,编写槽函数,
void Widget::on_btnSendContext_clicked()
{
int writeCnt = 0;
const char* sendata = ui->lineEditSendContext->text().toStdString().c_str(); //从ui控件上获取发送的数据
writeCnt = serialPort->write(sendata); //将数据写入串口,成功返回写入字节数,失败返回-1
if(writeCnt == -1){
ui->labelSendStatus->setText("SendError!");
}else{
writeCntTotal += writeCnt;
ui->labelSendStatus->setText("SendOK!");
ui->labelSendcnt->setNum(writeCntTotal);
//记录不显示重复字符
if(strcmp(sendata,SenderBak.toStdString().c_str()) != 0){ //str1 < str2 返回负数 ,str1 = str2返回0, str1 > str2 返回正数
ui->textEditRecord->append(sendata);
SenderBak = QString(sendata);
}
}
}
接收:
首先要实现自发自收功能要绑定信号与槽
connect(serialPort,&QSerialPort::readyRead,this,&Widget::on_serialData_reached);
信号:QSerialPort::readyRead
槽(自定义):Widget::on_serialData_reached
void Widget::on_serialData_reached()
{
QString revMessage = serialPort->readAll(); //读取串口
if(revMessage != NULL){
readCntTotal += revMessage.size();
qDebug() << "getMessage: "<< revMessage;
ui->textEditRev->append(revMessage);
ui->labelRevcnt->setNum(readCntTotal);
}
}
3.5 串口调试助手实现自动发送功能(QTimer)
timer = new QTimer(this); //为整个窗口添加一个定时器
connect(timer,&QTimer::timeout,this,[=](){
on_btnSendContext_clicked();
}); //绑定timer信号,到点就发送
void Widget::on_checkBoxSendInTime_clicked(bool checked)
{
if(checked){
ui->lineEditTimeeach->setEnabled(false);
ui->lineEditSendContext->setEnabled(false);
timer->start(ui->lineEditTimeeach->text().toUInt()); //设置
}else{
timer->stop();
ui->lineEditTimeeach->setEnabled(true);
ui->lineEditSendContext->setEnabled(true);
}
}
3.6 串口调试助手保存清空接收按键
void Widget::on_btnrevClear_clicked()
{
ui->textEditRev->clear();
}
void Widget::on_btnrevSave_clicked()
{
QString fileName = QFileDialog::getSaveFileName(this, tr("Save File"),
"C:/Users/qzh/Desktop/serialData.txt",
tr("Text files(*.txt)"));
if(fileName != NULL){
QFile file(fileName);
if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
return;
QTextStream out(&file);
out << ui->textEditRev->toPlainText();
file.close();
}
}
3.7 获取当前系统时间(QDateTime)
//设置定时器触发
QTimer *getSysTimer = new QTimer(this);
connect(getSysTimer,SIGNAL(timeout()),this,SLOT(time_reflash())); //绑定定时器刷新时间-通过高频率获取和显示达到时间更新效果
getSysTimer->start(100);
//获取当前时间
void Widget::getSysTime()
{
QDateTime currentDateTime = QDateTime::currentDateTime();
QDate date = currentDateTime.date();
int year = date.year();
int month = date.month();
int day = date.day();
QTime time = currentDateTime.time();
int hour = time.hour();
int minute = time.minute();
int second = time.second();
//QString myTime = QString("%1-%2-%3 %4:%5:%6", year,month,day,hour,time.minute(),time.second());
//占位符构造QString 类型
myTime = QString("%1-%2-%3 %4:%5:%6")
.arg(year,2,10,QChar('0'))
.arg(month,2,10,QChar('0'))
.arg(day,2,10,QChar('0'))
.arg(hour,2,10,QChar('0'))
.arg(minute,2,10,QChar('0'))
.arg(second,2,10,QChar('0'));
ui->labelCurrentTime->setText(myTime);
ui->labelCurrentTime->setText(myTime);
}
//更新时间
void Widget::time_reflash()
{
getSysTime();
}
3.8 接收时间并显示
法1:
在头文件中设置时间标志位
bool timeFlag = false;
void Widget::on_serialData_reached() //读取串口数据
{
QString revMessage = serialPort->readAll(); //读取串口
if(revMessage != NULL){
readCntTotal += revMessage.size();
qDebug() << "getMessage: "<< revMessage;
if(!timeFlag){
ui->textEditRev->append(revMessage);
}else{
QString mes = "[" +myTime +"]" + revMessage;
ui->textEditRev->append(mes);
}
ui->labelRevcnt->setText("Received:" + QString::number(readCntTotal));
}
}
void Widget::on_checkBoxRevTime_clicked(bool checked)
{
if(checked){
timeFlag = true;
}else{
timeFlag = false;
}
}
法2:ui->checkBoxRevTime->checkState()
void Widget::on_serialData_reached() //读取串口数据
{
QString revMessage = serialPort->readAll(); //读取串口
if(revMessage != NULL){
qDebug() << "getMessage: "<< revMessage;
if(ui->checkBoxRevTime->checkState() == Qt::Unchecked){
ui->textEditRev->append(revMessage);
}else if(ui->checkBoxRevTime->checkState() == Qt::Checked){
QString mes = "[" +myTime +"]" + revMessage;
ui->textEditRev->append(mes);
}
readCntTotal += revMessage.size();
ui->labelRevcnt->setText("Received:" + QString::number(readCntTotal));
}
}
3.9 HEX显示(QByteArray)(to编码,from解码)
void Widget::on_checkBoxHexDisplay_clicked(bool checked)
{
if(checked){
//1.读取textEdit的内容
QString tmp = ui->textEditRev->toPlainText();
//2.转换成HEX显示
QByteArray qtmp = tmp.toUtf8(); //QString的a(UTF-8)转换成 QByteArray的a(UTF-8)
qtmp = qtmp.toHex(); //QByteArray的a(UTF-8)转换成 QByteArray的61(HEX) -- 编码
//3.显示
QString lastShow;
tmp = QString::fromUtf8(qtmp);
for(int i=0; i <tmp.size();i+=2){
lastShow += tmp.mid(i,2) + " "; //tmp.mid(i,2) -- 获得tmp字符第i个字符之后的两个字符
}
ui->textEditRev->setText(lastShow.toUpper()); //QByteArray HEX的61 转换成QString 61 //toUpper()大写显示
}else{
//1.读取textEdit内容 .hex
QString tmpHexString = ui->textEditRev->toPlainText();
QByteArray tmpHexQByteArry = tmpHexString.toUtf8(); //QString 61(HEX) 转换成QByteArray 61(UTF-8)
QByteArray tmpQByteString = QByteArray::fromHex(tmpHexQByteArry); //QByteArray的61 转成QByteArray的a -- 解码
ui->textEditRev->setText(QString::fromUtf8(tmpQByteString)); //QByteArray转换成字符串
}
}
3.10 串口调试助手,发送HEX发送
void Widget::on_btnSendContext_clicked() //发送串口数据
{
int writeCnt = 0;
const char* sendata = ui->lineEditSendContext->text().toLocal8Bit().constData(); //从ui控件上获取发送的数据
if(ui->checkBoxHexSend->isChecked()){ //检查HEX发送是否被勾选
QString tmp = ui->lineEditSendContext->text();
//判断是否是偶数位
QByteArray tmpArry = tmp.toLocal8Bit();
if(tmpArry.size() % 2 != 0){
ui->labelSendStatus->setText("ErroR Input");
return;
}
//判断是否是符合十六进制表达
for(char c : tmpArry){
if(!std::isxdigit(c)){ //判断每一个字符是否是十六进制
ui->labelSendStatus->setText("ErroR Input");
return;
}
}
//转换成16进制发送,用书输入1,变成1,拒绝变成字符1 ,ASCII:49
QByteArray arrySend = QByteArray::fromHex(tmpArry);
writeCnt = serialPort->write(arrySend); //将数据写入串口,成功返回写入字节数,失败返回-1
}else{
writeCnt = serialPort->write(sendata); //将数据写入串口,成功返回写入字节数,失败返回-1
if(writeCnt == -1){
ui->labelSendStatus->setText("SendError!");
}else{
writeCntTotal += writeCnt;
ui->labelSendStatus->setText("SendOK!");
//ui->labelSendcnt->setNum(writeCntTotal);
ui->labelSendcnt->setText("Sent:" + QString::number(writeCntTotal));
//记录不显示重复字符
if(strcmp(sendata,SenderBak.toStdString().c_str()) != 0){ //str1 < str2 返回负数 ,str1 = str2返回0, str1 > str2 返回正数
ui->textEditRecord->append(sendata);
SenderBak = QString::fromUtf8(sendata);
}
}
}
}
3.11 串口调试助手添加换行功能
// 接收和发送两端同步
void Widget::on_btnSendContext_clicked() //发送串口数据
{
int writeCnt = 0;
const char* sendata = ui->lineEditSendContext->text().toLocal8Bit().constData(); //从ui控件上获取发送的数据
if(ui->checkBoxHexSend->isChecked()){
QString tmp = ui->lineEditSendContext->text();
//判断是否是偶数位
QByteArray tmpArry = tmp.toLocal8Bit();
if(tmpArry.size() % 2 != 0){
ui->labelSendStatus->setText("ErroR Input");
return;
}
//判断是否是符合十六进制表达
for(char c : tmpArry){
if(!std::isxdigit(c)){ //判断每一个字符是否是十六进制
ui->labelSendStatus->setText("ErroR Input");
return;
}
}
if(ui->checkBoxSendNewLine->isChecked()) //发送新行
tmpArry.append("\r\n");
//转换成16进制发送,用书输入1,变成1,拒绝变成字符1 ,ASCII:49
QByteArray arrySend = QByteArray::fromHex(tmpArry);
writeCnt = serialPort->write(arrySend); //将数据写入串口,成功返回写入字节数,失败返回-1
}else{
if(ui->checkBoxSendNewLine->isChecked()){
QByteArray arrySendData(sendata,strlen(sendata));
arrySendData.append("\r\n");
writeCnt = serialPort->write(arrySendData);
}else
writeCnt = serialPort->write(sendata); //将数据写入串口,成功返回写入字节数,失败返回-1
}
//发送失败的清空
if(writeCnt == -1){
ui->labelSendStatus->setText("SendError!");
}else{
writeCntTotal += writeCnt;
ui->labelSendStatus->setText("SendOK!");
//ui->labelSendcnt->setNum(writeCntTotal);
ui->labelSendcnt->setText("Sent:" + QString::number(writeCntTotal));
//记录不显示重复字符
if(strcmp(sendata,SenderBak.toStdString().c_str()) != 0){ //str1 < str2 返回负数 ,str1 = str2返回0, str1 > str2 返回正数
ui->textEditRecord->append(sendata);
SenderBak = QString::fromUtf8(sendata);
}
}
}
void Widget::on_serialData_reached() //读取串口数据
{
QString revMessage = serialPort->readAll(); //读取串口
if(revMessage != NULL){
if(ui->checkBoxLine->isChecked()) revMessage.append("\r\n"); //自动换行被按下
if(ui->checkBoxHexDisplay->isChecked()){
QByteArray tmpHexString = revMessage.toUtf8().toHex(); //将缓存的内容(新发的内容)转成HEX
//原来旧的内容先读出来
QString tmpStringHex = ui->textEditRev->toPlainText(); //保存旧的内容
tmpHexString = tmpStringHex.toUtf8() + tmpHexString; //旧的内容转成QByteArry类型+新的内容
ui->textEditRev->setText(QString::fromUtf8(tmpHexString));
}else{
qDebug() << "getMessage: "<< revMessage;
if(ui->checkBoxRevTime->checkState() == Qt::Unchecked){
ui->textEditRev->insertPlainText(revMessage);
}else if(ui->checkBoxRevTime->checkState() == Qt::Checked){
QString mes = "[" +myTime +"]" + revMessage;
ui->textEditRev->insertPlainText(mes); //不换行添加
}
readCntTotal += revMessage.size();
ui->labelRevcnt->setText("Received:" + QString::number(readCntTotal));
}
}
}
3.12 隐藏和显示
void Widget::on_btnHideTable_clicked(bool checked)
{
if(checked){
ui->btnHideTable->setText("拓展面板");
ui->groupBoxTexts->hide();
}else{
ui->btnHideTable->setText("隐藏面板");
ui->groupBoxTexts->show();
}
}
void Widget::on_btnHideHistory_clicked(bool checked)
{
if(checked){
ui->btnHideHistory->setText("显示历史");
ui->groupBoxRecord->hide();
}else{
ui->btnHideHistory->setText("隐藏历史");
ui->groupBoxRecord->show();
}
}
3.13 自定义ComboBox完成串口号列表的刷新
将QComboBox提升为MyComboBox
自定义信号与槽
重写鼠标点击事件
事件关联
3.14 通过子控件组控制子控件(相同类型)(通过设置属性传参)
/*
1.构造子控件名字
2.通过名字找到相应子控件
3.设置子控件id
4.进行信号与槽的绑定
*/
QList<QPushButton *> buttons; //构建QPushButton数组
for(int i=1; i<=9; i++){
QString btnName = QString("pushButton_%1").arg(i); //设置按钮名字
QPushButton* btn = findChild<QPushButton *>(btnName); //找到相应得子控件
if(btn){
btn->setProperty("buttonId",i); //设置buttonId为i
buttons.append(btn);
connect(btn,SIGNAL(clicked()),this,SLOT(on_command_button_clicked())); //绑定信号与槽
}
}
槽:
/*
1.获得相应发送信号的控件
2.进行槽函数功能的编写
*/
void Widget::on_command_button_clicked()
{
QPushButton *btn = qobject_cast<QPushButton *>(sender()); //获得发送信号的对象的名字,并返回QPushButton类型
if(btn){
int num = btn->property("buttonId").toInt();
qDebug() << num;
QString lineEditName = QString("lineEdit_%1").arg(num); //构建匹配的发送文本的名字
QLineEdit *lineEide = findChild<QLineEdit *>(lineEditName); //找到对应名字的子控件
if(lineEide){
ui->lineEditSendContext->setText(lineEide->text());
}
QString checkBoxName = QString("checkBox_%1").arg(num);
QCheckBox *checkBox = findChild<QCheckBox *>(checkBoxName);
if(checkBox){
ui->checkBoxHexSend->setChecked(checkBox->isChecked()); //设置checkBoxHexSend控件的状态
}
on_btnSendContext_clicked(); //发送数据
}
}
3.15 定时器循环发送
/*
Qt的ui界面本身有自己的线程,通过对ui界面本身的线程进行操作会出现问题,
如对进行sleep操作,ui整个界面会停止刷新所以不能在qt的ui线程中延时,否则导致页面的刷新问题,所以有以下两种方法解决问题
法1:定时器---QTimer
法2:多线程---QThread-
缺点:线程是写死的
*/
3.15.1 定时器(QTimer)
定义全局变量:
QTimer *buttonsConTimer;
int buttonIndex
初始化绑定信号与槽
buttonsConTimer = new QTimer(this);
connect(buttonsConTimer,&QTimer::timeout,this,&Widget::buttons_handler);
//槽函数-通过定时周期性触发
void Widget::buttons_handler()
{
if(buttonIndex < buttons.size()){
QPushButton *btnTmp = buttons[buttonIndex];
emit btnTmp->clicked(); //手动触发按键
buttonIndex++;
}else{
buttonIndex = 0;
}
}
//定时器开关通过检测checkBox状态
void Widget::on_checkBox_send_clicked(bool checked)
{
if(checked){
ui->spinBox->setEnabled(false);
buttonsConTimer->start(ui->spinBox->text().toUInt()); //打开定时器
}else{
ui->spinBox->setEnabled(true);
buttonsConTimer->stop(); //关闭定时器
}
}
3.15.2 多线程(QThread-重写run函数)
逻辑与定时器一致,只不过从定时器操作变成了线程操作
需要重写run()函数,所以定义了一个新的QThread类继承于QThread
3.16 重置按键对话框定制
QList<QPushButton *> buttons; //构建QPushButton数组
QList<QLineEdit *> lineEdits; //构建QLineEdit数组
QList<QCheckBox *> checkBoxs; //构建QCheckBox数组
//初始化
for(int i=1; i<=9; i++){
QString btnName = QString("pushButton_%1").arg(i); //设置按钮名字
QPushButton* btn = findChild<QPushButton *>(btnName); //找到相应得子控件
if(btn){
btn->setProperty("buttonId",i); //设置buttonId为i
buttons.append(btn);
connect(btn,SIGNAL(clicked()),this,SLOT(on_command_button_clicked())); //绑定信号与槽
}
QString lineEditName = QString("lineEdit_%1").arg(i);
QLineEdit *LineEdit = findChild<QLineEdit *>(lineEditName);
lineEdits.append(LineEdit);
QString checkBoxName = QString("checkBox_%1").arg(i);
QCheckBox *checkBox = findChild<QCheckBox *>(checkBoxName);
checkBoxs.append(checkBox);
}
void Widget::on_btnInit_clicked()
{
QMessageBox msgBox;
msgBox.setWindowTitle("提示");
msgBox.setIcon(QMessageBox::Question);
msgBox.setText("重置列表不可逆确认是否重置");
//msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
QPushButton *yesButton = msgBox.addButton("是",QMessageBox::YesRole);
QPushButton *noButton = msgBox.addButton("否",QMessageBox::NoRole);
msgBox.exec();
if(msgBox.clickedButton() == yesButton){
for(int i=0;i<lineEdits.size();i++){
//遍历lineEdit,并清空
lineEdits[i]->clear();
//遍历CheckBox,并取消勾选
checkBoxs[i]->setChecked(false);
}
}
if(msgBox.clickedButton() == noButton){
}
}
3.17 保存
void Widget::on_btnSave_clicked()
{
QString fileName = QFileDialog::getSaveFileName(this, tr("Save File"),
"C:/Users/qzh/Desktop",
tr("Text files (*.txt)"));
QFile file(fileName);
if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
return;
QTextStream out(&file);
for(int i=0; i<lineEdits.size(); i++){
out << checkBoxs[i]->isChecked() << "," <<lineEdits[i]->text() << "\n";
}
file.close();
}
3.18 载入
void Widget::on_btnLoad_clicked()
{
int i = 0;
QString fileName = QFileDialog::getOpenFileName(this, tr("打开文件"),
"C:/Users/qzh/Desktop",
tr("Text files (*.txt)"));
if(fileName != NULL){
QFile file(fileName);
if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
return;
QTextStream in(&file);
while(!in.atEnd() && i < lineEdits.size()){
QString line = in.readLine();
QStringList parts = line.split(","); //split按,分割成两部分,前半部分parts[0]- checkbox状态和后半部分parts[1]- 内容
if(parts.count() == 2){
checkBoxs[i]->setChecked(parts[0].toInt());
lineEdits[i]->setText(parts[1]);
}
i++;
}
}
}
4. 打包
找到qt的bin文件安装路径例(我的):D:\qt\5.12.9\mingw73_32\bin
win+r 打开cmd
进入打包的文件所在的位置:
E:\qtproject\2-Chuankou\build-1-Serial-001-ui-Desktop_Qt_5_12_9_MinGW_32_bit-Release\release
执行:D:\qt\5.12.9\mingw73_32\bin\windeployqt.exe + 生成的.exe
例:D:\qt\5.12.9\mingw73_32\bin\windeployqt.exe 1-Serial-001-ui.exe
最后将以下文件复制添加到release中
5. 总结-代码整合
5.1 头文件
文件名:customthread.h
内容:
#ifndef CUSTOMTHREAD_H
#define CUSTOMTHREAD_H
#include <QThread>
#include <QWidget>
class CustomThread : public QThread
{
Q_OBJECT
public:
CustomThread(QWidget *parent = nullptr);
protected:
void run() override;
signals:
void threadTimeOut();
};
#endif // CUSTOMTHREAD_H
文件名:mycombobox.h
内容:
#ifndef MYCOMBOBOX_H
#define MYCOMBOBOX_H
#include <QComboBox>
class MyComboBox : public QComboBox
{
Q_OBJECT //发送信号的宏
public:
MyComboBox(QWidget *parent = nullptr);
protected:
void mousePressEvent(QMouseEvent *e) override;
signals:
void refresh();
};
#endif // MYCOMBOBOX_H
文件名:widget.h
内容:
#ifndef WIDGET_H
#define WIDGET_H
#include <QSerialPortInfo>
#include <QDebug>
#include <QWidget>
#include <QSerialPort>
#include <QTimer>
#include <QPushButton>
#include "customthread.h"
#include <QFileDialog>
#include <QMessageBox>
#include <QTime>
#include <QByteArray>
#include <QThread>
#include "mycombobox.h"
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
private slots:
void on_btnCloseOrOpen_clicked();
void on_btnSendContext_clicked();
void on_serialData_reached();
void on_btnCloseOrOpen_clicked(bool checked);
void on_checkBoxSendInTime_clicked(bool checked);
void on_btnrevClear_clicked();
void on_btnrevSave_clicked();
void time_reflash();
void on_checkBoxHexDisplay_clicked(bool checked);
void on_btnHideTable_clicked(bool checked);
void on_btnHideHistory_clicked(bool checked);
void refreshSerialName();
void on_command_button_clicked();
void on_checkBox_send_clicked(bool checked);
void buttons_handler();
void on_btnInit_clicked();
void on_btnSave_clicked();
void on_btnLoad_clicked();
private:
Ui::Widget *ui;
QSerialPort *serialPort;
int writeCntTotal;
int readCntTotal;
QString SenderBak;
bool serialStatus = false; //打开关闭标志位
QTimer *timer;
QString myTime;
void getSysTime();
QTimer *buttonsConTimer;
QList<QPushButton *> buttons; //构建QPushButton数组
QList<QLineEdit *> lineEdits; //构建QLineEdit数组
QList<QCheckBox *> checkBoxs; //构建QCheckBox数组
int buttonIndex;
CustomThread *myThread;
};
#endif // WIDGET_H
5.1 .cpp
文件名:customthread.h
内容:
#include "customthread.h"
CustomThread::CustomThread(QWidget *parent) : QThread(parent)
{
}
void CustomThread::run()
{
while(true){
msleep(1000);
emit threadTimeOut();
}
}
文件名:main.h
内容:
#include "widget.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}
文件名:mycombobox.cpp
内容:
#include "mycombobox.h"
#include <QMouseEvent>
MyComboBox::MyComboBox(QWidget *parent) : QComboBox(parent)
{
}
void MyComboBox::mousePressEvent(QMouseEvent *e)
{
//发送信号
if(e->button() == Qt::LeftButton){
emit refresh();
}
QComboBox::mousePressEvent(e);
}
文件名:widget.cpp
内容:
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
//设置布局
ui->setupUi(this);
this->setLayout(ui->gridLayoutGlobal);
//实例化一个串口对象
serialPort = new QSerialPort(this);
timer = new QTimer(this); //为整个窗口添加一个定时器
buttonsConTimer = new QTimer(this);
connect(buttonsConTimer,&QTimer::timeout,this,&Widget::buttons_handler);
buttonIndex = 0;
writeCntTotal = 0;
readCntTotal = 0;
// //定时器
// QTimer *getSysTimer = new QTimer(this);
// connect(getSysTimer,SIGNAL(timeout()),this,SLOT(time_reflash())); //绑定定时器刷新时间
// getSysTimer->start(100);
//线程触发
myThread = new CustomThread(this);
connect(myThread,&CustomThread::threadTimeOut,this,&Widget::buttons_handler);
connect(serialPort,&QSerialPort::readyRead,this,&Widget::on_serialData_reached); //绑定接收
connect(timer,&QTimer::timeout,this,[=](){
on_btnSendContext_clicked();
}); //定时发送
connect(ui->comboBox_serialNum,&MyComboBox::refresh,this,&Widget::refreshSerialName);
//设置打开界面默认参数
ui->comboBox_boautrate->setCurrentIndex(6);
ui->comboBox_databit->setCurrentIndex(3);
ui->btnSendContext->setEnabled(false);
ui->checkBoxSendInTime->setEnabled(false);
ui->checkBoxSendNewLine->setEnabled(false);
ui->checkBoxHexSend->setEnabled(false);
ui->btnSave->setEnabled(false);
ui->btnInit->setEnabled(false);
ui->btnLoad->setEnabled(false);
//获取可用串口
//[static] QList<QSerialPortInfo> QSerialPortInfo::availablePorts()
refreshSerialName();
ui->labelSendStatus->setText(ui->comboBox_serialNum->currentText() + " Not Open");
for(int i=1; i<=9; i++){
QString btnName = QString("pushButton_%1").arg(i); //设置按钮名字
QPushButton* btn = findChild<QPushButton *>(btnName); //找到相应得子控件
if(btn){
btn->setProperty("buttonId",i); //设置buttonId为i
buttons.append(btn);
connect(btn,SIGNAL(clicked()),this,SLOT(on_command_button_clicked())); //绑定信号与槽
}
QString lineEditName = QString("lineEdit_%1").arg(i);
QLineEdit *LineEdit = findChild<QLineEdit *>(lineEditName);
lineEdits.append(LineEdit);
QString checkBoxName = QString("checkBox_%1").arg(i);
QCheckBox *checkBox = findChild<QCheckBox *>(checkBoxName);
checkBoxs.append(checkBox);
}
}
Widget::~Widget()
{
delete ui;
}
/*
* --首先实例化串口对象而后配置串口参数
1.选择端口号
2.配置波特率
3.配置数据位
4.配置校验位
5.配置停止位
6.流控
*/
/*
enum Parity {
NoParity = 0,
EvenParity = 2,
OddParity = 3,
SpaceParity = 4,
MarkParity = 5,
UnknownParity = -1
};
*/
void Widget::on_btnCloseOrOpen_clicked()
{
/*
if(!serialStatus){ //打开时
//1.选择端口号
serialPort->setPortName(ui->comboBox_serialNum->currentText());
//2.配置波特率
serialPort->setBaudRate(ui->comboBox_boautrate->currentText().toInt());
//3.配置数据位
serialPort->setDataBits(QSerialPort::DataBits(
ui->comboBox_databit->currentText().toUInt()));
//4.配置校验位
switch (ui->comboBox_jiaoyan->currentIndex()) {
case 0:
serialPort->setParity(QSerialPort::NoParity);
break;
case 1:
serialPort->setParity(QSerialPort::EvenParity);
break;
case 2:
serialPort->setParity(QSerialPort::MarkParity);
break;
case 3:
serialPort->setParity(QSerialPort::OddParity);
break;
case 4:
serialPort->setParity(QSerialPort::SpaceParity);
break;
default:
serialPort->setParity(QSerialPort::UnknownParity);
break;
}
//5.配置停止位
serialPort->setStopBits(QSerialPort::StopBits(
ui->comboBox_stopbit->currentText().toUInt()));
//6.配置流控
if(ui->comboBox_fileCon->currentText() == "None"){
serialPort->setFlowControl(QSerialPort::NoFlowControl);
}
//7.打开串口
if(serialPort->open(QIODevice::ReadWrite)){ //打开状态
qDebug() << "serial open success";
ui->comboBox_databit->setEnabled(false); //使其失效
ui->comboBox_fileCon->setEnabled(false); //使其失效
ui->comboBox_jiaoyan->setEnabled(false); //使其失效
ui->comboBox_stopbit->setEnabled(false); //使其失效
ui->comboBox_boautrate->setEnabled(false); //使其失效
ui->comboBox_serialNum->setEnabled(false); //使其失效
ui->btnCloseOrOpen->setText(QString("关闭串口"));
ui->btnSendContext->setEnabled(true);
serialStatus = true;
}else{ //打开失败
QMessageBox msgBox;
msgBox.setWindowTitle("打开串口错误");
msgBox.setText("打开失败,串口可能被占用.");
msgBox.exec();
}
}else{ //关闭时
serialPort->close();
ui->btnCloseOrOpen->setText("打开串口");
ui->comboBox_databit->setEnabled(true); //使其失效
ui->comboBox_fileCon->setEnabled(true); //使其失效
ui->comboBox_jiaoyan->setEnabled(true); //使其失效
ui->comboBox_stopbit->setEnabled(true); //使其失效
ui->comboBox_boautrate->setEnabled(true); //使其失效
ui->comboBox_serialNum->setEnabled(true); //使其失效
ui->btnSendContext->setEnabled(false);
serialStatus = false;
}*/
}
void Widget::on_btnSendContext_clicked() //发送串口数据
{
int writeCnt = 0;
const char* sendata = ui->lineEditSendContext->text().toLocal8Bit().constData(); //从ui控件上获取发送的数据
if(ui->checkBoxHexSend->isChecked()){
QString tmp = ui->lineEditSendContext->text();
//判断是否是偶数位
QByteArray tmpArry = tmp.toLocal8Bit();
if(tmpArry.size() % 2 != 0){
ui->labelSendStatus->setText("ErroR Input");
return;
}
//判断是否是符合十六进制表达
for(char c : tmpArry){
if(!std::isxdigit(c)){ //判断每一个字符是否是十六进制
ui->labelSendStatus->setText("ErroR Input");
return;
}
}
if(ui->checkBoxSendNewLine->isChecked()) //发送新行
tmpArry.append("\r\n");
//转换成16进制发送,用书输入1,变成1,拒绝变成字符1 ,ASCII:49
QByteArray arrySend = QByteArray::fromHex(tmpArry);
writeCnt = serialPort->write(arrySend); //将数据写入串口,成功返回写入字节数,失败返回-1
}else{
if(ui->checkBoxSendNewLine->isChecked()){
QByteArray arrySendData(sendata,strlen(sendata));
arrySendData.append("\r\n");
writeCnt = serialPort->write(arrySendData);
}else
writeCnt = serialPort->write(sendata); //将数据写入串口,成功返回写入字节数,失败返回-1
}
//发送失败的清空
if(writeCnt == -1){
ui->labelSendStatus->setText("SendError!");
}else{
writeCntTotal += writeCnt;
ui->labelSendStatus->setText("SendOK!");
//ui->labelSendcnt->setNum(writeCntTotal);
ui->labelSendcnt->setText("Sent:" + QString::number(writeCntTotal));
//记录不显示重复字符
if(strcmp(sendata,SenderBak.toStdString().c_str()) != 0){ //str1 < str2 返回负数 ,str1 = str2返回0, str1 > str2 返回正数
ui->textEditRecord->append(sendata);
SenderBak = QString::fromUtf8(sendata);
}
}
}
void Widget::on_serialData_reached() //读取串口数据
{
QString revMessage = serialPort->readAll(); //读取串口
if(revMessage != NULL){
if(ui->checkBoxLine->isChecked()) revMessage.append("\r\n"); //自动换行被按下
if(ui->checkBoxHexDisplay->isChecked()){
QByteArray tmpHexString = revMessage.toUtf8().toHex().toUpper(); //将缓存的内容(新发的内容)转成HEX
//原来旧的内容先读出来
QString tmpStringHex = ui->textEditRev->toPlainText(); //保存旧的内容
tmpHexString = tmpStringHex.toUtf8() + tmpHexString; //旧的内容转成QByteArry类型+新的内容
ui->textEditRev->setText(QString::fromUtf8(tmpHexString));
}else{
qDebug() << "getMessage: "<< revMessage;
if(ui->checkBoxRevTime->checkState() == Qt::Unchecked){
ui->textEditRev->insertPlainText(revMessage);
}else if(ui->checkBoxRevTime->checkState() == Qt::Checked){
QString mes = "[" +myTime +"]" + revMessage;
ui->textEditRev->insertPlainText(mes); //不换行添加
}
}
readCntTotal += revMessage.size();
ui->labelRevcnt->setText("Received:" + QString::number(readCntTotal));
ui->textEditRev->moveCursor(QTextCursor::End); //将光标移动至尾部
ui->textEditRev->ensureCursorVisible();
//ui->textEditRev->setFocus();
}
}
void Widget::on_btnCloseOrOpen_clicked(bool checked)
{
if(checked){ //打开时
//1.选择端口号
serialPort->setPortName(ui->comboBox_serialNum->currentText());
//2.配置波特率
serialPort->setBaudRate(ui->comboBox_boautrate->currentText().toInt());
//3.配置数据位
serialPort->setDataBits(QSerialPort::DataBits(
ui->comboBox_databit->currentText().toUInt()));
//4.配置校验位
switch (ui->comboBox_jiaoyan->currentIndex()) {
case 0:
serialPort->setParity(QSerialPort::NoParity);
break;
case 1:
serialPort->setParity(QSerialPort::EvenParity);
break;
case 2:
serialPort->setParity(QSerialPort::MarkParity);
break;
case 3:
serialPort->setParity(QSerialPort::OddParity);
break;
case 4:
serialPort->setParity(QSerialPort::SpaceParity);
break;
default:
serialPort->setParity(QSerialPort::UnknownParity);
break;
}
//5.配置停止位
serialPort->setStopBits(QSerialPort::StopBits(
ui->comboBox_stopbit->currentText().toUInt()));
//6.配置流控
if(ui->comboBox_fileCon->currentText() == "None"){
serialPort->setFlowControl(QSerialPort::NoFlowControl);
}
//7.打开串口
if(serialPort->open(QIODevice::ReadWrite)){ //打开状态
qDebug() << "serial open success";
ui->comboBox_databit->setEnabled(false); //使其失效
ui->comboBox_fileCon->setEnabled(false); //使其失效
ui->comboBox_jiaoyan->setEnabled(false); //使其失效
ui->comboBox_stopbit->setEnabled(false); //使其失效
ui->comboBox_boautrate->setEnabled(false); //使其失效
ui->comboBox_serialNum->setEnabled(false); //使其失效
ui->btnCloseOrOpen->setText(QString("关闭串口"));
ui->btnSendContext->setEnabled(true);
ui->checkBoxSendInTime->setEnabled(true);
ui->checkBoxSendNewLine->setEnabled(true);
ui->checkBoxHexSend->setEnabled(true);
ui->btnSave->setEnabled(true);
ui->btnInit->setEnabled(true);
ui->btnLoad->setEnabled(true);
// serialStatus = true;
ui->labelSendStatus->setText(ui->comboBox_serialNum->currentText() + " isOpen");
}else{ //打开失败
QMessageBox msgBox;
msgBox.setWindowTitle("打开串口错误");
msgBox.setText("打开失败,串口可能被占用.");
msgBox.exec();
}
}else{ //关闭时
serialPort->close();
ui->btnCloseOrOpen->setText("打开串口");
ui->comboBox_databit->setEnabled(true); //使其失效
ui->comboBox_fileCon->setEnabled(true); //使其失效
ui->comboBox_jiaoyan->setEnabled(true); //使其失效
ui->comboBox_stopbit->setEnabled(true); //使其失效
ui->comboBox_boautrate->setEnabled(true); //使其失效
ui->comboBox_serialNum->setEnabled(true); //使其失效
ui->btnSendContext->setEnabled(false);
ui->checkBoxSendInTime->setEnabled(false);
ui->checkBoxSendNewLine->setEnabled(false);
ui->checkBoxHexSend->setEnabled(false);
ui->btnSave->setEnabled(false);
ui->btnInit->setEnabled(false);
ui->btnLoad->setEnabled(false);
ui->checkBoxSendInTime->setCheckState(Qt::Unchecked);
timer->stop(); //关闭定时器
ui->lineEditTimeeach->setEnabled(true);
ui->lineEditSendContext->setEnabled(true);
// serialStatus = false;
ui->labelSendStatus->setText(ui->comboBox_serialNum->currentText() + " isClose");
}
}
void Widget::on_checkBoxSendInTime_clicked(bool checked)
{
if(checked){
ui->lineEditTimeeach->setEnabled(false);
ui->lineEditSendContext->setEnabled(false);
timer->start(ui->lineEditTimeeach->text().toUInt()); //设置
}else{
timer->stop();
ui->lineEditTimeeach->setEnabled(true);
ui->lineEditSendContext->setEnabled(true);
}
}
void Widget::on_btnrevClear_clicked()
{
ui->textEditRev->clear();
}
void Widget::on_btnrevSave_clicked()
{
QString fileName = QFileDialog::getSaveFileName(this, tr("Save File"),
"C:/Users/qzh/Desktop/serialData.txt",
tr("Text files(*.txt)"));
if(fileName != NULL){
QFile file(fileName);
if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
return;
QTextStream out(&file);
out << ui->textEditRev->toPlainText();
file.close();
}
}
void Widget::time_reflash()
{
getSysTime();
ui->labelCurrentTime->setText(myTime);
}
void Widget::getSysTime()
{
QDateTime currentDateTime = QDateTime::currentDateTime();
QDate date = currentDateTime.date();
int year = date.year();
int month = date.month();
int day = date.day();
QTime time = currentDateTime.time();
int hour = time.hour();
int minute = time.minute();
int second = time.second();
//QString myTime = QString("%1-%2-%3 %4:%5:%6", year,month,day,hour,time.minute(),time.second());
//占位符构造QString 类型
myTime = QString("%1-%2-%3 %4:%5:%6")
.arg(year,2,10,QChar('0'))
.arg(month,2,10,QChar('0'))
.arg(day,2,10,QChar('0'))
.arg(hour,2,10,QChar('0'))
.arg(minute,2,10,QChar('0'))
.arg(second,2,10,QChar('0'));
}
void Widget::on_checkBoxHexDisplay_clicked(bool checked)
{
if(checked){
//1.读取textEdit的内容
QString tmp = ui->textEditRev->toPlainText();
//2.转换成HEX显示
QByteArray qtmp = tmp.toUtf8(); //QString的a(UTF-8)转换成 QByteArray的a(UTF-8)
qtmp = qtmp.toHex(); //QByteArray的a(UTF-8)转换成 QByteArray的61(HEX) -- 编码
//3.显示
QString lastShow;
tmp = QString::fromUtf8(qtmp);
for(int i=0; i <tmp.size();i+=2){
lastShow += tmp.mid(i,2) + " "; //tmp.mid(i,2) -- 获得tmp字符第i个字符之后的两个字符
}
ui->textEditRev->setText(lastShow.toUpper()); //QByteArray HEX的61 转换成QString 61 //toUpper()大写显示
}else{
//1.读取textEdit内容 .hex
QString tmpHexString = ui->textEditRev->toPlainText();
QByteArray tmpHexQByteArry = tmpHexString.toUtf8(); //QString 61(HEX) 转换成QByteArray 61(UTF-8)
QByteArray tmpQByteString = QByteArray::fromHex(tmpHexQByteArry); //QByteArray的61 转成QByteArray的a -- 解码
ui->textEditRev->setText(QString::fromUtf8(tmpQByteString)); //QByteArray转换成字符串
}
ui->textEditRev->moveCursor(QTextCursor::End);
ui->textEditRev->ensureCursorVisible();
}
void Widget::on_btnHideTable_clicked(bool checked)
{
if(checked){
ui->btnHideTable->setText("拓展面板");
ui->groupBoxTexts->hide();
}else{
ui->btnHideTable->setText("隐藏面板");
ui->groupBoxTexts->show();
}
}
void Widget::on_btnHideHistory_clicked(bool checked)
{
if(checked){
ui->btnHideHistory->setText("显示历史");
ui->groupBoxRecord->hide();
}else{
ui->btnHideHistory->setText("隐藏历史");
ui->groupBoxRecord->show();
}
}
void Widget::refreshSerialName()
{
ui->comboBox_serialNum->clear();
//获取可用串口
//[static] QList<QSerialPortInfo> QSerialPortInfo::availablePorts()
QList<QSerialPortInfo> serialList = QSerialPortInfo::availablePorts(); //获取可用的串口列表
for(QSerialPortInfo serialinfo : serialList){ //迭代器迭代遍历
qDebug() << serialinfo.portName();
ui->comboBox_serialNum->addItem(serialinfo.portName()); //将可用的串口添加到串口中
}
ui->labelSendStatus->setText("Com Refresh");
}
void Widget::on_command_button_clicked()
{
QPushButton *btn = qobject_cast<QPushButton *>(sender()); //获得发送信号的对象的名字,并返回QPushButton类型
if(btn){
int num = btn->property("buttonId").toInt();
qDebug() << num;
QString lineEditName = QString("lineEdit_%1").arg(num); //构建匹配的发送文本的名字
QLineEdit *lineEide = findChild<QLineEdit *>(lineEditName); //找到对应名字的子控件
if(lineEide){
if(lineEide->text().size() <= 0) return;
ui->lineEditSendContext->setText(lineEide->text());
}
QString checkBoxName = QString("checkBox_%1").arg(num);
QCheckBox *checkBox = findChild<QCheckBox *>(checkBoxName);
if(checkBox){
ui->checkBoxHexSend->setChecked(checkBox->isChecked()); //设置checkBoxHexSend控件的状态
}
on_btnSendContext_clicked(); //发送数据
}
}
void Widget::buttons_handler()
{
if(buttonIndex < buttons.size()){
QPushButton *btnTmp = buttons[buttonIndex];
emit btnTmp->clicked(); //手动触发按键
buttonIndex++;
}else{
buttonIndex = 0;
}
}
/*
不能在qt的ui线程中延时,否则导致页面的刷新问题
法1:定时器
法2:多线程
*/
void Widget::on_checkBox_send_clicked(bool checked)
{
if(checked){
ui->spinBox->setEnabled(false);
myThread->start();
// buttonsConTimer->start(ui->spinBox->text().toUInt()); //打开定时器
}else{
ui->spinBox->setEnabled(true);
myThread->terminate();
// buttonsConTimer->stop(); //关闭定时器
}
}
void Widget::on_btnInit_clicked()
{
QMessageBox msgBox;
msgBox.setWindowTitle("提示");
msgBox.setIcon(QMessageBox::Question);
msgBox.setText("重置列表不可逆确认是否重置");
//msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
QPushButton *yesButton = msgBox.addButton("是",QMessageBox::YesRole);
QPushButton *noButton = msgBox.addButton("否",QMessageBox::NoRole);
msgBox.exec();
if(msgBox.clickedButton() == yesButton){
for(int i=0;i<lineEdits.size();i++){
//遍历lineEdit,并清空
lineEdits[i]->clear();
//遍历CheckBox,并取消勾选
checkBoxs[i]->setChecked(false);
}
}
if(msgBox.clickedButton() == noButton){
}
}
void Widget::on_btnSave_clicked()
{
QString fileName = QFileDialog::getSaveFileName(this, tr("保存文件"),
"C:/Users/qzh/Desktop",
tr("Text files (*.txt)"));
QFile file(fileName);
if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
return;
QTextStream out(&file);
for(int i=0; i<lineEdits.size(); i++){
out << checkBoxs[i]->isChecked() << "," <<lineEdits[i]->text() << "\n";
}
file.close();
}
void Widget::on_btnLoad_clicked()
{
int i = 0;
QString fileName = QFileDialog::getOpenFileName(this, tr("打开文件"),
"C:/Users/qzh/Desktop",
tr("Text files (*.txt)"));
if(fileName != NULL){
QFile file(fileName);
if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
return;
QTextStream in(&file);
while(!in.atEnd() && i < lineEdits.size()){
QString line = in.readLine();
QStringList parts = line.split(","); //split按,分割成两部分,前半部分parts[0]- checkbox状态和后半部分parts[1]- 内容
if(parts.count() == 2){
checkBoxs[i]->setChecked(parts[0].toInt());
lineEdits[i]->setText(parts[1]);
}
i++;
}
}
}
链接:https://pan.baidu.com/s/1cKTUxDyDg6J7PcVLvj9Ltg
提取码:nr0g
--来自百度网盘超级会员V5的分享