QtQuick串口编程Demo

一、目标:

实现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++方法


四、运行结果:

QtQuick串口编程Demo_第1张图片


五、补充:

本界面风格使用的谷歌Style=Material,该风格定义在qtquickcontrols2.conf配置文件中

你可能感兴趣的:(QtQuick)