一开始想用Qml写一个简单的串口助手来熟悉Qml是如何和C++来进行交互的。Qml用来写我们所见到的界面,C++完成背后的逻辑处理,有点类似于前端和后端的概念。在实现多线程的过程中用了一些时间,在这里记录一下交互和多线程的实现。
因为要在Qml中访问C++类或对象,对C++类有这两点要求
1.类必须继承自QObject类或其导出类
2.类首添加QObject宏
这两条要求是把这个类加入Qt的元对象系统中,只有使用元对象系统,一个类的方法和属性才可以通过字符串的形式的名字来调用,才具有在QML中访问的基础条件
在Qml中访问C++类或对象,有如下的方式
1.信号和槽
2.具有Q_INVOKABLE 宏方法
3.具有Q_ENUMS宏的枚举
4.具有Q_PROPERTY宏的属性
在Qml中和C++交互,有两种方式
1.将C++类注册到Qml中,在Qml中完成类的实例化
2.将C++类的实例注册为Qml的上下文属性,可在Qml中直接引用该实例
a)先来看第一种方式,C++类注册到Qml中
要达到在Qml中访问C++类的目的,要将这个类注册为Qml的可用类型,注册方法如下
- qmlRegisterType : 可在Qml里面直接进行构造实例并访问
- qmlRegisterUncreatableType : 可在C++里面以属性的方式进行访问,但不可以在qml前端进行访问
- qmlRegisterSingltonType : 注册Qml单例,Qml中可通过 inporm相应包的方式进行访问
注册之后就可以在Qml中像普通控件一样使用C++类的实例,前提要import C++类导出的包
再来看第二种方式,C++类的实例注册为Qml的上下文属性
1.在main函数中,如果用QQuickView加载Qml文件
>2在main函数中,如果用QQmlApplicationEngine加载Qml文件
因为在C++中对串口类进行操作很方便,所以采用第二种方式,将串口类的实例导入Qml中的上下文属性。
#ifndef MYSERIALPORT_H
#define MYSERIALPORT_H
#include <QtSerialPort/QSerialPort>
#include <QtSerialPort/QSerialPortInfo>
#include <QObject>
class MySerialPort : public QObject
{
Q_OBJECT
Q_PROPERTY(bool linkStatus READ linkStatus NOTIFY linkStatusChanged)
Q_PROPERTY(QStringList portName READ portName NOTIFY portNameChanged)
Q_PROPERTY(QString strDisplay READ strDisplay NOTIFY strDisplayChanged)//这里没有用到
public:
explicit MySerialPort(QObject *parent = nullptr);
QList<QSerialPortInfo> availablePorts();
static bool isSystemPort(QSerialPortInfo *port);
QStringList portName()const{
return myPortName;
}
bool linkStatus()const{
return myLinkStatus;
}
QString strDisplay()const{
return hexStrDisplay;
}
Q_INVOKABLE void serialPortOperate(int PortNameIndex,int BaudRateIndex,int StopbitsIndex,int DatabitsIndex,int ParityIndex);
private:
QSerialPort *mySerialPort;
bool myLinkStatus=false; //true connected false unconnected
QList<QSerialPortInfo> mySerialPortInfoList;
QStringList myPortName;
QString hexStrDisplay;
signals:
void portNameChanged(QStringList);
void linkStatusChanged(bool);
void strDisplayChanged(QString);
void bytesReceived(QByteArray data);
public slots:
void readMyCom();
};
#endif // MYSERIALPORT_H
在这个类中我用Q_PROPERTY注册了三个属性供Qml访问,三个属性portName 、linkStatus 、strDisplay 的Changed信号发射后自动会更改前端中使用了这三个属性的控件属性。还有一个有Q_INVOKABLE宏操作串口的函数,接收前端发来的Indexs来打开串口。我在这里并没有定义定时器来定时检测串口,所以先插串口设备在运行哦
#include "myserialport.h"
#include <mavlink.h> //这里我的目的是接收串口字节流解析mavlink消息
#include <QDebug>
MySerialPort::MySerialPort(QObject *parent) : QObject(parent){
mySerialPortInfoList = availablePorts();
qDebug() << "run myserialport class constructor" ;
}
QList<QSerialPortInfo> MySerialPort::availablePorts(void){
QList<QSerialPortInfo> list;
foreach(QSerialPortInfo portInfo, QSerialPortInfo::availablePorts()) {
if (!isSystemPort(&portInfo)) {
list << *((QSerialPortInfo*)&portInfo);
qDebug() << "portName :" << portInfo.portName(); //调试时可以看的串口信息
qDebug() << "Description :" << portInfo.description();
qDebug() << "Manufacturer:" << portInfo.manufacturer();
myPortName.append(portInfo.portName());
}
}
emit portNameChanged(myPortName); //通知前端comNameCombox下拉菜单更新
return list;
}
bool MySerialPort::isSystemPort(QSerialPortInfo* port){
// Known operating system peripherals that are NEVER a peripheral
// that we should connect to.
// XXX Add Linux (LTE modems, etc) and Windows as needed
// MAC OS
if (port->systemLocation().contains("tty.MALS")
|| port->systemLocation().contains("tty.SOC")
|| port->systemLocation().contains("tty.Bluetooth-Incoming-Port")
// We open these by their cu.usbserial and cu.usbmodem handles
// already. We don't want to open them twice and conflict
// with ourselves.
|| port->systemLocation().contains("tty.usbserial")
|| port->systemLocation().contains("tty.usbmodem")) {
return true;
}
return false;
}
void MySerialPort::serialPortOperate(int PortNameIndex, int BaudRateIndex, int StopbitsIndex, int DatabitsIndex, int ParityIndex){
qDebug() << "run myserialport operator" ;
if(myLinkStatus==false) // 目前尚无连接
{
qDebug()<<"portNameIndex:"<<QString::number(PortNameIndex);
qDebug()<<"baudNameIndex:"<<QString::number(BaudRateIndex);
qDebug()<<"stopNameIndex:"<<QString::number(StopbitsIndex);
qDebug()<<"dataNameIndex:"<<QString::number(DatabitsIndex);
qDebug()<<"parityNameIndex:"<<QString::number(ParityIndex);
mySerialPort = new QSerialPort(); //串口类对象的实例化
if (mySerialPort->isOpen()){
qDebug("COM already open");
return;
}
mySerialPort->setPortName(myPortName[PortNameIndex]);
mySerialPort->setBaudRate(115200);
mySerialPort->setDataBits(QSerialPort::Data8);
mySerialPort->setParity(QSerialPort::NoParity);
mySerialPort->setFlowControl( QSerialPort::NoFlowControl );
mySerialPort->setStopBits(QSerialPort::OneStop);
myLinkStatus = mySerialPort->open(QIODevice::ReadWrite);
if(myLinkStatus){
mySerialPort->setDataTerminalReady(true);
qDebug() << mySerialPort->portName() + " is open";
}else {
qDebug("Uart not exist or being occupied");
return;
}
emit linkStatusChanged(myLinkStatus);//通知前端连接状态变化
//串口类对象的实例化,后连接readyRead信号 到本类的 readMyCom槽
connect(mySerialPort,SIGNAL(readyRead()),this,SLOT(readMyCom()),Qt::QueuedConnection);
//connect(mySerialPort, &MySerialPort::bytesReceived, _mavlinkProtocol, &MAVLinkProtocol::receiveBytes);
} else //存在连接 要断开
{
if((mySerialPort->isOpen()))
{
qDebug() << mySerialPort->portName() + " is close";
mySerialPort->clear();
mySerialPort->close();
mySerialPort->deleteLater();
myLinkStatus=false;
emit linkStatusChanged(myLinkStatus);//通知前端连接状态变化
}
}
}
void MySerialPort::readMyCom()
{
qint64 byteCount = mySerialPort->bytesAvailable();
if (byteCount) {
QByteArray buffer;
buffer.resize(byteCount);
mySerialPort->read(buffer.data(), buffer.size());
emit bytesReceived(buffer); //通知解析类
}
else {
// Error occurred
qWarning() << "Serial port not readable";
}
}
在构造函数中调用availablePorts函数检测可用串口,并且将port name加入myPortName这个QStringList类型变量中,在发射portNameChanged信号通知前端显示串口号。在前端的Button的onClicked槽中调用serialPortOperate并传入Index参数来配置串口,我在这里简化了只用了portNameIndex来选择串口号,其他的采用默认配置。在serialPortOperate实例化串口类对象并连接readyRead槽到本类的读取函数readMyCom中,在readMyCom中发射bytesReceived通知解析类来解析字节流。
接下来在Main函数中注册类的实例为Qml上下文属性
MySerialPort *myport = new MySerialPort();
QObject::connect(myport, &MySerialPort::bytesReceived,myMavlinkProtocol, &MAVLinkProtocol::receiveBytes);//串口接收的字节流到解析类
QQmlApplicationEngine engine;
engine.rootContext()->setContextProperty("MySerialPort",myport);
engine.rootContext()->setContextProperty("MavlinkProtocol",myMavlinkProtocol);
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
if (engine.rootObjects().isEmpty())
return -1;
在来看Qml文件
import QtQuick 2.9
import QtQuick.Controls 2.2
//import an.qt.MySerialPort 1.0
Page {
objectName: "COMConfigurePage";
width: 600
height: 400
title:qsTr("Uart Conncet");
Column{
id:comConfigureLayout;
anchors.verticalCenter: parent.verticalCenter;
anchors.horizontalCenter: parent.horizontalCenter;
spacing:15;
Row{
id:comRowLayout;
spacing:15;
Label{
id:comLabel;
width:25;
anchors.verticalCenter: parent.verticalCenter;
text: qsTr("Com")
wrapMode: Text.WordWrap
horizontalAlignment: Text.AlignHCenter
}
ComboBox{
objectName: "comCombox1";
id:comCombox;
height: 35;
anchors.verticalCenter: parent.verticalCenter;
model:MySerialPort.portName;
}
}
Row{
id:baudRowLayout;
spacing:15;
Label{
id:baudLabel;
width:25;
anchors.verticalCenter: parent.verticalCenter;
text: qsTr("Baud")
wrapMode: Text.WordWrap
horizontalAlignment: Text.AlignHCenter
}
ComboBox{
objectName: "baudCombox";
id:baudCombox;
height: 35;
anchors.verticalCenter: parent.verticalCenter;
model: ["9600","115200","230400","460800"];
}
}
Row{
id:stopRowLayout;
spacing:15;
Label{
id:stopLabel;
width:25;
anchors.verticalCenter: parent.verticalCenter;
text: qsTr("Stop")
wrapMode: Text.WordWrap
horizontalAlignment: Text.AlignHCenter
}
ComboBox{
objectName: "stopCombox";
id:stopCombox;
height: 35;
anchors.verticalCenter: parent.verticalCenter;
model: ["1","1.5","2"];
}
}
Row{
id:dataRowLayout;
spacing:15;
Label{
id:dataLabel;
width:25;
anchors.verticalCenter: parent.verticalCenter;
text: qsTr("Data")
wrapMode: Text.WordWrap
horizontalAlignment: Text.AlignHCenter
}
ComboBox{
objectName: "dataCombox";
id:dataCombox;
height: 35;
anchors.verticalCenter: parent.verticalCenter;
model: ["8","7","6","5"];
}
}
Row{
id:parityRowLayout;
spacing:15;
Label{
id:parityLabel;
width:25;
anchors.verticalCenter: parent.verticalCenter;
text: qsTr("Parity")
wrapMode: Text.WordWrap
horizontalAlignment: Text.AlignHCenter
}
ComboBox{
objectName: "parityCombox";
id:parityCombox;
height: 35;
anchors.verticalCenter: parent.verticalCenter;
model: ["NoParity","Even","Odd"];
}
}
Row{
id:operateRowLayout;
spacing:15;
Label{
id:operateLabel;
width:25;
anchors.verticalCenter: parent.verticalCenter;
text: qsTr("Operate")
wrapMode: Text.WordWrap
horizontalAlignment: Text.AlignHCenter
}
Button{
objectName: "operateBtn";
id:operateBtn;
width:140
height: 35;
anchors.verticalCenter: parent.verticalCenter;
text:"Open"; onClicked:MySerialPort.serialPortOperate(comCombox.currentIndex,baudCombox.currentIndex,stopCombox.currentIndex,dataCombox.currentIndex,parityCombox.currentIndex);
}
}
}
Connections{
target:MySerialPort;
onLinkStatusChanged:{
if(MySerialPort.linkStatus==true){
operateBtn.text="Close";
comCombox.enabled=false;
baudCombox.enabled=false;
stopCombox.enabled=false;
dataCombox.enabled=false;
parityCombox.enabled=false;
}
else{
operateBtn.text="Open";
comCombox.enabled=true;
baudCombox.enabled=true;
stopCombox.enabled=true;
dataCombox.enabled=true;
parityCombox.enabled=true;
}
}
}
}
Qml文件中以一个列布局中定义6个行布局类展示 Label和 Combox 以及最后一行的Button的。显示串口号的Combox中有个model是C++中的属性MySerialPort.portName ,这里的MySerialPort是在main函数中注册的上下文属性。在Button的onClicked槽中调用C++函数,onClicked:MySerialPort.serialPortOperate(comCombox.currentIndex,baudCombox.currentIndex,stopCombox.currentIndex,dataCombox.currentIndex,parityCombox.currentIndex);
带走currentIndex属性到前端操作串口。最后一个Connections连接了C++中linkStatusChanged信号到Qml中更改ComBox使能属性和Button文本。
运行结果如下,我是用Qt 5.11中自带的Qt Quick Stack模板,有个Stack切换三个Page
可以看到能够稳定的解析Mavlink消息
我们知道在Qt中多线程的实现通常有两种方法,
1.自定义的类继承字QThread,并重新实现父类中的虚函数run
2.利用moveToThread
先来看第一种,定义MyThread类继承字QThread,重新实现run函数
#ifndef MYTHREAD_H
#define MYTHREAD_H
#include <QObject>
#include <QDebug>
#include <QThread>
#include <QtSerialPort/QSerialPort>
#include <QtSerialPort/QSerialPortInfo>
class MyThread : public QThread
{
Q_OBJECT
public:
MyThread(QString *portName);
void run();
public slots:
void read_serial_data();//读取串口数据
private:
QSerialPort *my_serialPort_thread;
QByteArray MyByteArray_thread;
QByteArray DataToAnalysis_thread;
public:
QString port_Name;
};
#endif // MYTHREAD_H
在MyThread.cpp中
#include "mythread.h"
#include <QDebug>
#include <QMessageBox>
#include <QByteArray>
#include <QEventLoop>
MyThread::MyThread(QString *portName){
port_Name=*portName;
}
void MyThread::run(){
my_serialPort_thread = new QSerialPort();
if (my_serialPort_thread->isOpen()) {
qDebug("COM already open");
return;
}
my_serialPort_thread->setPortName(port_Name);
my_serialPort_thread->setBaudRate(115200);//波特率
my_serialPort_thread->setDataBits(QSerialPort::Data8);
my_serialPort_thread->setParity(QSerialPort::NoParity);
my_serialPort_thread->setFlowControl( QSerialPort::NoFlowControl );
my_serialPort_thread->setStopBits(QSerialPort::OneStop);
bool flag = my_serialPort_thread->open( QIODevice::ReadWrite );
if(flag==false) {
qDebug("Uart not exist or being occupied");
return;
}else {
my_serialPort_thread->setDataTerminalReady(true);
qDebug() << my_serialPort_thread->portName() + " is open";
}
connect(my_serialPort_thread,SIGNAL(readyRead()),this,SLOT(read_serial_data()));
QEventLoop eventLoop;
eventLoop.exec();
}
void MyThread::read_serial_data()
{
qDebug()<<"SerialReadThread:" <<currentThreadId();
QString strDisplay_thread;
QByteArray byte_data = my_serialPort_thread->readAll();
if(!byte_data.isEmpty())
{
MyByteArray_thread.append(byte_data);
}
}
这里需要注意的是在run中开始事件循环,否则默认不开启,运行完run中的代码,此线程就结束了,开始事件循环才能在槽中接收到字节。然而脱离的run函数的串口读取槽,并没有在新的线程中运行,而只有run函数中的代码在新线程中等待事件循环。可以通过线程ID查看,这里就不看了。
再来看第二种,利用moveToThread
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
QThread mySerialPortThread;
MySerialPort *myport = new MySerialPort();
myport->moveToThread(&mySerialPortThread);
mySerialPortThread.start();
MAVLinkProtocol *myMavlinkProtocol = new MAVLinkProtocol();
QObject::connect(myport, &MySerialPort::bytesReceived,myMavlinkProtocol, &MAVLinkProtocol::receiveBytes);
QQmlApplicationEngine engine;
engine.rootContext()->setContextProperty("MySerialPort",myport);
engine.rootContext()->setContextProperty("MavlinkProtocol",myMavlinkProtocol);
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
if (engine.rootObjects().isEmpty())
return -1;
return app.exec();
}
运行后报如下错误
哎,因为要再Qml中访问C++类的属性,将该实例注册到了Qml的上下文,在将该实例moveToThread到另外一个线程,这个C++类和Qml引擎不再同一个线程里……醉了,Qml中这种方法也不能使用……吐血
还好天无绝人之路,CSDN找到了一个CopyFile的例程,给我了启发,再写一个串口和Qml交互的中间类不就可以了吗?接着撸代码吧,这次讲解不细了,直接贴代码吧,只要搞过串口的应该都看的懂
myserialport.h //这里不再有再Qml中需要访问的属性和方法,并定义了一个Timer检查串口设备变化
#ifndef MYSERIALPORT_H
#define MYSERIALPORT_H
#include <QObject>
#include <QtSerialPort/QSerialPort>
#include <QtSerialPort/QSerialPortInfo>
#include <QDebug>
#include <QTimer>
#include <QThread>
class MySerialPort : public QObject
{
Q_OBJECT
public:
explicit MySerialPort(QObject *parent = nullptr);
QStringList getMyPortName(){ return myPortName; }
bool getLinkStatus(){return myLinkStatus;}
signals:
void bytesReceived(QByteArray data);
void linkStatusChanged(bool linkStatus);
void portNameReady(QStringList portName);
public slots:
void serialPortOperate(int portNameIndex,int baudRateIndex,int stopbitsIndex,int databitsIndex,int parityIndex , int flowCtrlIndex);
void readMyCom();
void checkMySerialPortEvent();
private:
QList<QSerialPortInfo> availablePorts() ;
static bool isSystemPort(QSerialPortInfo *port);
private:
QSerialPort *mySerialPort;
QList<QSerialPortInfo> mySerialPortInfoList;
QStringList myPortName;
bool myLinkStatus=false;
QTimer *mySerialPortCheckTimer;
};
#endif // MYSERIALPORT_H
myserialport.cpp
#include "myserialport.h"
MySerialPort::MySerialPort(QObject *parent) : QObject(parent)
{
// qDebug()<<"MySerialPort constructor thread:" <
mySerialPortInfoList = availablePorts();
mySerialPortCheckTimer= new QTimer(this);
connect(mySerialPortCheckTimer, SIGNAL(timeout()), this, SLOT(checkMySerialPortEvent()));
mySerialPortCheckTimer->start(1000);
// qDebug() << "run MySerialPort Class Constructor" ;
}
void MySerialPort::serialPortOperate(int portNameIndex, int baudRateIndex, int stopbitsIndex, int databitsIndex, int parityIndex, int flowCtrlIndex)
{
// qDebug() << "run myserialport operator" ;
if(myLinkStatus==false) // 目前尚无连接
{
// qDebug()<<"portNameIndex:"<
// qDebug()<<"baudRateIndex:"<
// qDebug()<<"stopbitsIndex:"<
// qDebug()<<"databitsIndex:"<
// qDebug()<<"parityIndex:"<
// qDebug()<<"FlowCtrlIndex:"<
mySerialPort = new QSerialPort();
if (mySerialPort->isOpen()){
qDebug("COM already open");
return;
}
mySerialPort->setPortName(myPortName[portNameIndex]);
mySerialPort->setBaudRate(115200);
mySerialPort->setDataBits(QSerialPort::Data8);
mySerialPort->setParity(QSerialPort::NoParity);
mySerialPort->setFlowControl( QSerialPort::NoFlowControl );
mySerialPort->setStopBits(QSerialPort::OneStop);
myLinkStatus = mySerialPort->open(QIODevice::ReadWrite);
if(myLinkStatus){
mySerialPort->setDataTerminalReady(true);
qDebug() << mySerialPort->portName() + " is open";
emit linkStatusChanged(myLinkStatus);
}
else {
qDebug("Uart not exist or being occupied");
return;
} QObject::connect(mySerialPort,SIGNAL(readyRead()),this,SLOT(readMyCom()),Qt::QueuedConnection);
}
else //存在连接 要断开
{
if((mySerialPort->isOpen())){
qDebug() << mySerialPort->portName() + " is close";
mySerialPort->clear();
mySerialPort->close();
mySerialPort->deleteLater();
myLinkStatus=false;
emit linkStatusChanged(myLinkStatus);
}
}
}
void MySerialPort::readMyCom(){
// qDebug()<<"SerialReadThread:" <
qint64 byteCount = mySerialPort->bytesAvailable();
if (byteCount) {
QByteArray buffer;
buffer.resize(byteCount);
mySerialPort->read(buffer.data(), buffer.size());
emit bytesReceived(buffer);
}
else qWarning() << "Serial port not readable";
// qDebug()<<"SerialReadThread:" <
// QByteArray byte_data = mySerialPort->readAll();
// if(!byte_data.isEmpty())
// {
//// qDebug()<
// QString str = byte_data.toHex().data();
//// qDebug()<
//// str = str.toUpper ();
//// for(int i = 0;i
//// {
//// QString st = str.mid (i,2);
//// hexStrDisplay += st;
//// hexStrDisplay += " ";
//// }
// // emit strDisplayChanged(hexStrDisplay);
// }
}
void MySerialPort::checkMySerialPortEvent()
{
if(myLinkStatus==false){
availablePorts();
}else return;
}
QList<QSerialPortInfo> MySerialPort::availablePorts()
{
QList<QSerialPortInfo> list;
QStringList portNameLocal;
foreach(QSerialPortInfo portInfo, QSerialPortInfo::availablePorts()) {
if (!isSystemPort(&portInfo)) {
list << *((QSerialPortInfo*)&portInfo);
// qDebug() << "portName :" << portInfo.portName(); //调试时可以看的串口信息
// qDebug() << "Description :" << portInfo.description();
// qDebug() << "Manufacturer:" << portInfo.manufacturer();
portNameLocal<<(portInfo.portName());
myPortName = portNameLocal;
}
}
emit portNameReady(myPortName);
return list;
}
bool MySerialPort::isSystemPort(QSerialPortInfo *port)
{
// Known operating system peripherals that are NEVER a peripheral
// that we should connect to.
// XXX Add Linux (LTE modems, etc) and Windows as needed
// MAC OS
if (port->systemLocation().contains("tty.MALS")
|| port->systemLocation().contains("tty.SOC")
|| port->systemLocation().contains("tty.Bluetooth-Incoming-Port")
// We open these by their cu.usbserial and cu.usbmodem handles
// already. We don't want to open them twice and conflict
// with ourselves.
|| port->systemLocation().contains("tty.usbserial")
|| port->systemLocation().contains("tty.usbmodem")) {
return true;
}
return false;
}
myserialportqml.h //和Qml交互的类
#ifndef MYSERIALPORTQML_H
#define MYSERIALPORTQML_H
#include <QObject>
#include "myserialport.h"
#include <QThread>
class MySerialPortQml : public QObject
{
Q_OBJECT
Q_PROPERTY(QStringList portNameQml READ portNameQml NOTIFY portNameQmlChanged)
public:
explicit MySerialPortQml(QObject *parent = nullptr);
QStringList portNameQml()const{return myPortNameQml; }
Q_INVOKABLE void getSerialPortQmlIndex(int portNameIndex,int baudRateIndex,int stopbitsIndex,int databitsIndex,int parityIndex , int flowCtrlIndex);
signals:
void portNameQmlChanged(QStringList);
void portLinkStatusQmlChanged(bool linkStatus);
void setSerialPortQmlIndex(int portNameIndex,int baudRateIndex,int stopbitsIndex,int databitsIndex,int parityIndex , int flowCtrlIndex);
public slots:
void getPortName(QStringList portName);
void getSerialPortQmlLinkStatus(bool status);
public:
MySerialPort *myPortQml;
private:
QStringList myPortNameQml;
bool myPortQmlLinkStatus;
};
#endif // MYSERIALPORTQML_H
myserialportqml.cpp文件
#include "myserialportqml.h"
MySerialPortQml::MySerialPortQml(QObject *parent) : QObject(parent)
{
// qDebug()<<"MySerialPortQml constructor thread:" <
myPortQml = new MySerialPort();
myPortNameQml = myPortQml->getMyPortName();
QThread * childThread = new QThread();
myPortQml->moveToThread(childThread);
QObject::connect(childThread, &QThread::finished, childThread, &QObject::deleteLater);
childThread->start();
// qDebug()<<" port name from construction:"<
QObject::connect(myPortQml,SIGNAL(portNameReady(QStringList)),this,SLOT(getPortName(QStringList)));
QObject::connect(this,SIGNAL(setSerialPortQmlIndex(int,int,int,int,int,int)),myPortQml,SLOT(serialPortOperate(int,int,int,int,int,int)));
QObject::connect(myPortQml,SIGNAL(linkStatusChanged(bool)),this,SLOT(getSerialPortQmlLinkStatus(bool)));
// qDebug() << "run MySerialPortQml Class Constructor" ;
}
void MySerialPortQml::getSerialPortQmlIndex(int portNameIndex, int baudRateIndex, int stopbitsIndex, int databitsIndex, int parityIndex, int flowCtrlIndex)
{
emit setSerialPortQmlIndex(portNameIndex,baudRateIndex,stopbitsIndex,databitsIndex,parityIndex,flowCtrlIndex);
}
void MySerialPortQml::getPortName(QStringList portName)
{
// myPortNameQml.clear();
myPortNameQml=portName;
emit portNameQmlChanged(myPortNameQml);
// qDebug()<<"trig get port name slot:"<
}
void MySerialPortQml::getSerialPortQmlLinkStatus(bool status)
{
myPortQmlLinkStatus=status;
emit portLinkStatusQmlChanged(myPortQmlLinkStatus);
}
qml类就不贴了,基本和前面一样的。现在我觉得对于Qml中多线程的实现稍微麻烦一些,也许单纯依靠号信号和槽完成前端Qml和C++交互是更简单的方法,但我目前不想尝试了,主要是花在写博客的时间有点多了……
如果您觉得本文对您有些许帮助,可以小小打赏一下作者哦