一、目标:
实现QtQuick界面,操控串口通信,进行串口数据的接收和发送
二、核心思想:
利用Qt库的QSerialPort类,使用C++实现串口数据的逻辑通信,并接受QtQuick界面的参数设置,在QML中调用C++实现的函数进行实际的数据收发
(QML与C++混合编程)
三、具体实现:
(1)C++中的逻辑实现
首先看serialport.h文件
#ifndef SERIALPORT_H
#define SERIALPORT_H
#include
#include
class SerialPort : public QObject
{
Q_OBJECT
public:
explicit SerialPort(QObject *parent = nullptr);
~SerialPort();
Q_INVOKABLE bool serialConnect(QString port,QString baudrate,QString databits,QString parity,QString stopbits);
Q_INVOKABLE QString serialRead();
Q_INVOKABLE bool serialWrite(QString sendStr);
signals:
public slots:
private:
QSerialPort *m_serial;
};
#endif // SERIALPORT_H
其中,注册到QML环境中的类必须继承自QObject,在类中声明“Q_OBJECT”才能在C++中定义信号和槽,需要注册到QML环境中的,变量属性加关键字“Q_PROPERTY”,函数方法加关键字“Q_INVOKABLE”,定义了一个QSerialPort的对象,将在后续连接和通信中实现
serialport.cpp
#include "serialport.h"
SerialPort::SerialPort(QObject *parent) : QObject(parent)
{
m_serial = new QSerialPort;
}
bool SerialPort::serialConnect(QString port,QString baudrate,QString databits,QString parity,
QString stopbits)
{
m_serial->setPortName(port);
if(!m_serial->open(QIODevice::ReadWrite))
{
printf("Open Error");
return 0;
}
switch (baudrate.toInt()) {
case 4800:
m_serial->setBaudRate(QSerialPort::Baud4800);
break;
case 9600:
m_serial->setBaudRate(QSerialPort::Baud9600);
break;
case 115200:
m_serial->setBaudRate(QSerialPort::Baud115200); //设置波特率为115200
break;
default:
printf("BaudRate Error");
return 0;
}
switch (databits.toInt()) {
case 6:
m_serial->setDataBits(QSerialPort::Data6);
break;
case 7:
m_serial->setDataBits(QSerialPort::Data7);
break;
case 8:
m_serial->setDataBits(QSerialPort::Data8); //设置数据位8
break;
default:
printf("DataBits Error");
return 0;
}
switch (parity.toInt()) {
case 0:
m_serial->setParity(QSerialPort::NoParity); //校验位设置为0
break;
case 2:
m_serial->setParity(QSerialPort::EvenParity);
break;
case 3:
m_serial->setParity(QSerialPort::OddParity);
break;
default:
printf("Parity Error");
return 0;
}
switch (stopbits.toInt()) {
case 1:
m_serial->setStopBits(QSerialPort::OneStop); //停止位设置为1
break;
case 2:
m_serial->setStopBits(QSerialPort::TwoStop);
break;
case 3:
m_serial->setStopBits(QSerialPort::OneAndHalfStop);
break;
default:
printf("StopBits Error");
return 0;
}
m_serial->setFlowControl(QSerialPort::NoFlowControl);//设置为无流控制
return 1;
}
QString SerialPort::serialRead()
{
return m_serial->readAll();
}
bool SerialPort::serialWrite(QString sendStr)
{
if(m_serial->write(sendStr.toLatin1().data(),strlen(sendStr.toLatin1().data())))
return 1;
else
return 0;
}
SerialPort::~SerialPort()
{
if(m_serial->isOpen())
{
m_serial->clear();
m_serial->close();
}
m_serial->deleteLater();
}
与传统Qt中使用的函数一致,其中serialConnect函数中,接受Qt界面的参数设置,先打开串口,然后通过switch匹配,分别设置串口通信的串口名称、波特率、数据位、校验位、停止位
(2)将C++中的类注册到QML中
#include
#include
#include "serialport.h"
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
qmlRegisterType("an.qt.mySerialPort",1,0,"SerialPort");
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
if (engine.rootObjects().isEmpty())
return -1;
return app.exec();
}
关键在中间的一句使用qmlRegisterType进行注册,尖括号中为我们前面定义的新类名字,小括号中分别为import将要导入的名称,主、次版本号,QML中所能使用的对象名称为双引号中的SerialPort
(3)在QML中调用C++的逻辑实现
import QtQuick 2.0
import QtQuick.Controls 2.3
import QtQuick.Layouts 1.3
import an.qt.mySerialPort 1.0
Page{
SerialPort{
id:serialport;
}
header: ToolBar{
RowLayout{
anchors.fill: parent
Text{
text: qsTr("SerialPort客户端")
font.pointSize: 20
horizontalAlignment: Qt.AlignHCenter
Layout.fillWidth: true
}
}
}
GridLayout{
id:grid
anchors.verticalCenter: parent.verticalCenter;
anchors.left: parent.left;
anchors.leftMargin: 10;
rows:6;
rowSpacing: 5;
columns: 2;
columnSpacing: 5
Label{
text:qsTr("串口")
}
ComboBox{
id:port;
model: ["COM1","COM2","COM3"];
}
Label{
text:qsTr("波特率")
}
ComboBox{
id:baudrate;
model: ["4800","9600","115200"];
}
Label{
text:qsTr("数据位")
}
ComboBox{
id:databits
model: ["6","7","8"];
}
Label{
text:qsTr("校验位")
}
ComboBox{
id:parity
model: ["0","2","3"];
}
Label{
text:qsTr("停止位")
}
ComboBox{
id:stopbits
model: ["1","2","3"];
}
Button{
text: qsTr("打开串口")
highlighted: true
Layout.columnSpan: 2;
onClicked: {
serialport.serialConnect(port.currentText,baudrate.currentText,
databits.currentText,parity.currentText,stopbits.currentText);
}
}
}
ColumnLayout{
anchors.left: grid.right
anchors.leftMargin: 60;
anchors.verticalCenter: parent.verticalCenter
spacing: 5
TextArea{
id:receive;
Layout.preferredWidth: 200;
Layout.preferredHeight: 200;
text: qsTr("Receive:")
readOnly: true;
background: Rectangle{
color: "gray"
}
}
Button{
text: qsTr("接收数据")
highlighted: true;
onClicked: {
receive.append(serialport.serialRead());
}
}
TextField{
id:send;
Layout.preferredWidth: 200
}
Button{
text:qsTr("发送数据")
highlighted: true
onClicked: {
serialport.serialWrite(send.text)
}
}
}
}
注意前几行的导入方法“import an.qt.mySerialPort 1.0”,Page前几行中定义了我们将要使用的对象的id,在按钮槽函数中调用对象id所包含的C++方法
四、运行结果:
五、补充:
本界面风格使用的谷歌Style=Material,该风格定义在qtquickcontrols2.conf配置文件中