QT学习过程及简单串口和UDP通信demo开发过程及代码分享
2017-10-07 20:54
766 查看
写在前面
Qt是一个1991年由Qt Company开发的跨平台C++图形用户界面应用程序开发框架。它既可以开发GUI程序,也可用于开发非GUI程序,比如控制台工具和服务器。Qt是面向对象的框架,很容易扩展,允许真正地组件编程。Qt是同Windows平台上的 MFC,WPF,ATL等是同类型的东西。以前接触过一点MFC,也用MFC写过一些简单的界面程序,所以就和MFC做一些对比。和QT对比起来,从学习者的角度,笔者感觉QT更加容易掌握,当然这可能与有MFC的基础有关系。不过确实QT的帮助系统做的比MFC(或者直接说VS)比较好,随时随地F1就可以,尽管这需要一点英文水平。另外,QT比MFC在消息和事件处理方面的更加容易理解,QT的信号和槽简直就是天才的想法。
笔者接触QT不到半个月,但凭着c++和MFC的基础,已经对QT整体有了一个大体的把握。笔者一直认为,学习东西要奔着需求才能进步神速。别人出国半年就比你国内十几年英语水平高,你不学你出门连酱油都打不了。目前正需要做一个可以同时和串口,UDP通信的demo,借着这个机会就去了解了下QT。
笔者的学习过程大概是这样的。第一步,把QT的帮助文档目录浏览一遍,重点看了界面,信号和槽,串口和UDP部分。第二步,在界面上增加各种控件并进行布局,熟悉各种控件的功能和属性,控件布局。比如说在文本框打印著名的“hello world”。第三步,设计子对话框并能在主界面打开,在子对话框上增加控件并布局,主要是串口号,波特率,UDP端口这些。第四步,实现串口和UDP的通信,可以搜到现成的代码块,这时需要边看帮助文档边写代码边上网查。第五步,代码重组,把面向过程的代码封装成类。界面美化,加背景,控件加图标等等。等把这个demo做出来时,笔者的QT大概入门了。
在做这个demo的时候,参考了论坛360safe的一个demo程序和qgc地面站(开源),还有串口猎人的程序(没有源码,只看界面),在这里进行感谢。笔者把做好的demo程序也放到论坛上,希望更多的人可以学习,也欢迎留言,如果有什么不对的地方还欢迎批评指正,共同进步。
DEMO效果展示
中文和英文切换:子对话框(有点违和,是后来强行加进去的):
不同背景:
代码片段及注释
这部分主要是给笔者自己看的。笔者有个习惯(强迫症),喜欢删东西。所以做完的东西总是喜欢传到网上(当然是那种能公开的东西)。中英文切换
//main.cpp QTranslator translator_ch; translator_ch.load(QString(":/qm/TripleDebugger.qm")); app.installTranslator(&translator_ch); //mainwindow.cpp if(current_language == UI_ZH) { current_language = UI_EN; } else if(current_language == UI_EN) { current_language = UI_ZH; } switch(current_language) { case UI_EN: translator->load(QString(":/qm/TripleDebugger2.qm")); break; case UI_ZH: translator->load(QString(":/qm/TripleDebugger.qm")); break; } title_widget->translateLanguage(); setup_widget->setupserialwidget->controltranslate(); setup_widget->setuptcpwidge->controltranslate(); setup_widget->setupudpwidge->controltranslate(); sendandreceive_widget->controltranslate(); advancereceive_widget->controltranslate(); advancesend_widget->controltranslate();
多界面重叠切换
statked_widget = new QStackedWidget(); statked_widget->addWidget(setup_widget); statked_widget->addWidget(sendandreceive_widget); statked_widget->addWidget(advancereceive_widget); statked_widget->addWidget(advancesend_widget); statked_widget->addWidget(readme_widget); statked_widget->addWidget(about_widget); statked_widget->setContentsMargins(0,0,0,0);
界面布局
int space = 10; QVBoxLayout *v_label_layout = new QVBoxLayout(); v_label_layout->addWidget(labelserialnumber); v_label_layout->addSpacing(space); v_label_layout->addWidget(labelbaudrate); v_label_layout->addSpacing(space); v_label_layout->addWidget(labeldatabit); v_label_layout->addSpacing(space); v_label_layout->addWidget(labelstopbit); v_label_layout->addSpacing(space); v_label_layout->addWidget(labelparitybit); v_label_layout->addSpacing(space); v_label_layout->addWidget(pushButtonconnect); QVBoxLayout *v_combobox_layout = new QVBoxLayout(); v_combobox_layout->addWidget(comboBoxserialnumber); v_combobox_layout->addSpacing(space); v_combobox_layout->addWidget(comboBoxbaudrate); v_combobox_layout->addSpacing(space); v_combobox_layout->addWidget(comboBoxdatabit); v_combobox_layout->addSpacing(space); v_combobox_layout->addWidget(comboBoxstopbit); v_combobox_layout->addSpacing(space); v_combobox_layout->addWidget(comboBoxparitybit); v_combobox_layout->addSpacing(space); v_combobox_layout->addWidget(pushButtondisconnect); QHBoxLayout *h_setserial_layout = new QHBoxLayout(); h_setserial_layout->addLayout(v_label_layout); h_setserial_layout->addLayout(v_combobox_layout); QVBoxLayout *v_setserial_layout = new QVBoxLayout(); v_setserial_layout->addLayout(h_setserial_layout); v_setserial_layout->addSpacing(space); v_setserial_layout->addWidget(radioButtonintrodu 11397 ction); v_setserial_layout->addSpacing(space); v_setserial_layout->addWidget(radioButtonhardware); v_setserial_layout->addSpacing(space); v_setserial_layout->addWidget(radioButtonprotocol); v_setserial_layout->addSpacing(space); v_setserial_layout->addWidget(radioButtonasci); v_setserial_layout->addStretch(); QHBoxLayout *main_layout = new QHBoxLayout(); main_layout->addLayout(v_setserial_layout); main_layout->addWidget(textEdit); setLayout(main_layout); radioButtonintroduction->setChecked(true); show_introduction();
串口打开
//信号和槽,把按钮和函数连接起来 connect(pushButtonconnect,SIGNAL(clicked(bool)),this,SLOT(connectserial())); //类成员槽函数 private slots: void connectserial(); void disconnectserial(); //槽函数 void SetupSerialWidge::connectserial() { serialport->setPortName(getportnumber()); serialport->setBaudRate(getportbaudrate()); serialport->setDataBits(getportdatabit()); serialport->setParity(getportparitybit()); serialport->setStopBits(getportstopbit()); if(!serialport->isOpen()) { serialport->setFlowControl(QSerialPort::NoFlowControl); if(serialport->open(QIODevice::ReadWrite)) { qDebug() << "successful open serial"<< serialport->portName(); pushButtonconnect->setEnabled(false); pushButtondisconnect->setEnabled(true); } else { qDebug() << "failed"; } } else { qDebug() << "the serial port already open"; } }
串口关闭
//信号和槽,把按钮和函数连接起来 connect(pushButtondisconnect,SIGNAL(clicked(bool)),this,SLOT(disconnectserial())); //类成员槽函数 private slots: void connectserial(); void disconnectserial(); //槽函数 void SetupSerialWidge::disconnectserial() { if(serialport->isOpen()) { serialport->close(); pushButtonconnect->setEnabled(true); pushButtondisconnect->setEnabled(false); } else { qDebug() << "the serial port already closed"; } }
串口和UDP发送
if(tool == SERIAL) { if(issendstr) //以字符串方式发送 { QString str = textEditsend->toPlainText(); QByteArray ba = str.toLatin1(); serialport->write(ba); } else//以十六进制方式发送 { QString str = textEditsend->toPlainText();//从LineEdit得到字符串 QByteArray ba; StringToHex(str,ba);//将str字符串转换为16进制的形式 serialport->write(ba);//发送到串口 } } if(tool == UDP) { if(issendstr) //以字符串方式发送 { QString str = textEditsend->toPlainText(); QByteArray ba = str.toLatin1(); udp.udp_socket_tx->writeDatagram(ba, ba.size(), udp.IP_remote, udp.Port_Tx); } else//以十六进制方式发送 { QString str = textEditsend->toPlainText();//从LineEdit得到字符串 QByteArray ba; StringToHex(str,ba);//将str字符串转换为16进制的形式 udp.udp_socket_tx->writeDatagram(ba, ba.size(), udp.IP_remote, udp.Port_Tx); } }
串口接收
//serialport connect(serialport,SIGNAL(readyRead()),this,SLOT(on_serialdataready())); public slots: //serial void on_serialdataready(); void SendandReceiveWidge::on_serialdataready() { if(mode == SENDANDRECEIVE) { if(isreceivestr) { QByteArray requestData; requestData = serialport->readAll(); //读取数据 串口读取出来的数据类型 是QByteArray 不是QString textEditreceive->insertPlainText(requestData); textEditreceive->moveCursor(QTextCursor::End); } else { QByteArray requestData = serialport->readAll(); //显示到文本框 QDataStream out(&requestData,QIODevice::ReadWrite); //将字节数组读入 QString temp; while(!out.atEnd()) { qint8 outChar = 0; out>>outChar; //每字节填充一次,直到结束 //十六进制的转换 QString str = QString("%1").arg(outChar&0xFF,2,16,QLatin1Char('0')); temp+=str.toUpper()+" "; } textEditreceive->insertPlainText(temp);//每发送两个字符后添加一个空格 textEditreceive->moveCursor(QTextCursor::End); if(textEditreceive->toPlainText().length()>30000) { textEditreceive->clear(); } } } }
UDP接收
connect(udp.udp_socket_rx, SIGNAL(readyRead()),this, SLOT(on_udpdataready())); public slots: //udp void on_udpdataready(); void SendandReceiveWidge::on_udpdataready() { if(mode == SENDANDRECEIVE) { if(isreceivestr) { QByteArray requestData; while(udp.udp_socket_rx->hasPendingDatagrams()) { requestData.resize(udp.udp_socket_rx->pendingDatagramSize()); QHostAddress sender; quint16 senderPort; udp.udp_socket_rx->readDatagram(requestData.data(), requestData.size(), &sender, &senderPort); textEditreceive->insertPlainText(requestData); textEditreceive->moveCursor(QTextCursor::End); } } else { QByteArray requestData; QString templager; while(udp.udp_socket_rx->hasPendingDatagrams()) { requestData.resize(udp.udp_socket_rx->pendingDatagramSize()); QHostAddress sender; quint16 senderPort; udp.udp_socket_rx->readDatagram(requestData.data(), requestData.size(), &sender, &senderPort); //显示到文本框 QDataStream out(&requestData,QIODevice::ReadWrite); //将字节数组读入 QString temp; while(!out.atEnd()) { qint8 outChar = 0; out>>outChar; //每字节填充一次,直到结束 //十六进制的转换 QString str = QString("%1").arg(outChar&0xFF,2,16,QLatin1Char('0')); temp+=str.toUpper()+" "; } templager+=temp; } textEditreceive->insertPlainText(templager);//每发送两个字符后添加一个空格 textEditreceive->moveCursor(QTextCursor::End); if(textEditreceive->toPlainText().length()>30000) { textEditreceive->clear(); } } } else //必须有,猜测可能是udp缓存区有数如果不读,udp对象内部会崩溃但是程序不会报错。 { QByteArray requestData; while(udp.udp_socket_rx->hasPendingDatagrams()) { requestData.resize(udp.udp_socket_rx->pendingDatagramSize()); QHostAddress sender; quint16 senderPort; udp.udp_socket_rx->readDatagram(requestData.data(), requestData.size(), &sender, &senderPort); } } }
数据解析
void AdvancedReceiveWidge::on_serialdataready() { if(mode == ADVANCEDRECEIVE && isrun) { QByteArray requestData = serialport->readAll(); QDataStream out(&requestData,QIODevice::ReadWrite); //将字节数组读入 while(!out.atEnd()) { qint8 outChar = 0; out>>outChar; //每字节填充一次,直到结束 //十六进制的转换 QString str = QString("%1").arg(outChar&0xFF,2,16,QLatin1Char('0')); if(str == header||str.toUpper()==header) { count = 0; start = 1; } if(start == 1) { tempdata[count++] = str; } if(count == length && str == tail) { start = 0; info(tempdata); } } } } void AdvancedReceiveWidge::info(QString *tempdata) { int x1,x2,x3,x4; bool ok; QString xx[4]; xx[0] = tempdata[1]+tempdata[2];xx[1] = tempdata[3]+tempdata[4]; xx[2] = tempdata[5]+tempdata[6];xx[3] = tempdata[7]+tempdata[8]; x1 = xx[0].toInt(&ok,16); x2 = xx[1].toInt(&ok,16); x3 = xx[2].toInt(&ok,16); x4 = xx[3].toInt(&ok,16); QString show1 = QString::number(x1);QString show2 = QString::number(x2);QString show3 = QString::number(x3);QString show4 = QString::number(x4); QString show = show1+" "+show2+" "+show3+" "+show4+" "; textEdit->insertPlainText(show); textEdit->insertPlainText("\n"); textEdit->setTextCursor(cursor); } void AdvancedReceiveWidge::StringToHex(QString str, QByteArray &senddata) { int hexdata,lowhexdata; int hexdatalen = 0; int len = str.length(); senddata.resize(len/2); char lstr,hstr; for(int i=0; i<len; ) { //char lstr, hstr=str[i].toLatin1(); if(hstr == ' ') { i++; continue; } i++; if(i >= len) break; lstr = str[i].toLatin1(); hexdata = ConvertHexChar(hstr); lowhexdata = ConvertHexChar(lstr); if((hexdata == 16) || (lowhexdata == 16)) break; else hexdata = hexdata*16+lowhexdata; i++; senddata[hexdatalen] = (char)hexdata; hexdatalen++; } senddata.resize(hexdatalen); } char AdvancedReceiveWidge::ConvertHexChar(char ch) { if((ch >= '0') && (ch <= '9')) return ch-0x30; else if((ch >= 'A') && (ch <= 'F')) return ch-'A'+10; else if((ch >= 'a') && (ch <= 'f')) return ch-'a'+10; else return (-1); }
所有源代码地址
开发环境win10,qtcreator4.2.0,qt5.7.1.地址:资源刚刚上传,还在审核中,稍后在评论区上传。
相关文章推荐
- 黑马程序员_UDP和TCP简单的通信代码和注释学习笔记
- 1人30天44587行代码,分享舍得网开发过程
- SubSonic3.0 Demo1.0——应用了T4模版可减少开发过程中70%以上的代码量以及80%以上的出错率
- 基于linux简单的UDP网络通信代码
- WindowsPhone8 应用开发学习笔记(三) - UDP通信
- W5100 简单UDP 协议的开发与代码分析
- 1人30天44587行代码,分享舍得网开发过程
- java学习心得(一):代码的简单编译和解释的前期过程
- 通过简单手游打小三,学习手机网游的开发(进入6月,我们的仙剑demo在这个月完成,先插些别的东东)
- iPhone/iPad高级应用与手游开发学习笔记:sqlite3学习(简单英文生词本demo)
- Qt开发:TCP和UDP网络通信
- 个人学习代码保存:例8.在存储过程中使用简单的事务处理
- dubbo学习过程、使用经验分享及实现原理简单介绍
- android开发学习之 简单的demo SharedPreferences 的登陆账号密码保存和按键退出提醒
- 1人30天44587行代码,分享舍得网开发过程(转)
- 1人30天44587行代码,分享舍得网开发过程
- 【tcp-ip学习总结】基础UDP实现的简单通信功能小程序
- UNIX环境高级编程学习之第十六章网络IPC:套接字 - 简单UDP Socket 通信
- TCP/IP详解(卷2实现)学习笔记(一)udp的socket通信过程底层实现概述(1)
- jQuery学习笔记--jqGrid开发最新代码分享