您的位置:首页 > 编程语言 > Qt开发

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.

地址:资源刚刚上传,还在审核中,稍后在评论区上传。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  qt 串口 udp 界面 国际化