Qml使用cpp文件的信号槽

文章目录


一、C++文件Demo

Q_INVOKABLE是一个Qt元对象系统中的宏,用于将C++函数暴露给QML引擎。具体来说,它使得在QML代码中可以直接调用C++类中被标记为Q_INVOKABLE的成员函数。

cpp 复制代码
public:
    SerialPort();
    // 返回可用串口
    Q_INVOKABLE QStringList availablePorts();
    // 打开串口
    Q_INVOKABLE bool open(QString portName, QString buadRate, QString dataBits, QString stopBits,QString parity, QString flowControl);
    // 关闭串口
    Q_INVOKABLE void close();
    // 直接调用接口
    Q_INVOKABLE void say();

signals:
    //返回串口打开信息
    Q_INVOKABLE void openMsg(bool open, QString error);
    //接口,用于多线程
    Q_INVOKABLE void sendMsg(QString msg);

public slots:
    //
    void sendMsgSlot(QString msg);

private:
    QThread* m_thread;

    QSerialPort* m_port;

    QMutex m_mutex;
cpp 复制代码
m_port = new QSerialPort();
connect(this, &SerialPort::sendMsg, this, &SerialPort::sendMsgSlot);

tts = new QTextToSpeech(this);

m_thread = new QThread;
m_thread->setObjectName("串口线程");
this->moveToThread(m_thread);
connect(m_thread, &QThread::finished, this, &QThread::deleteLater);
connect(m_thread, &QThread::finished, this, &SerialPort::deleteLater);
m_thread->start();
cpp 复制代码
QStringList SerialPort::availablePorts()
{
    QStringList list;
    foreach(auto info, QSerialPortInfo::availablePorts()) list.append(info.portName());
    list<<"COM11"<<"COM22";
    return list;
}
cpp 复制代码
bool SerialPort::open(QString portName, QString buadRate, QString dataBits, QString stopBits,QString parity, QString flowControl)
{
    bool ok = false;
    QString errstr = "m_port异常";
    {
        QMutexLocker locker(&m_mutex);
        if(!m_port)
        {
            emit openMsg(false, errstr);
            locker.unlock();
            return false;
        }
        m_port->setPortName(portName);
        m_port->setBaudRate(buadRate.toInt());
        m_port->setDataBits((QSerialPort::DataBits)dataBits.toInt());
        m_port->setStopBits((QSerialPort::StopBits)stopBits.toInt());
        m_port->setParity((QSerialPort::Parity)parity.toInt());
        m_port->setFlowControl((QSerialPort::FlowControl)flowControl.toInt());
        ok = m_port->open(QIODevice::ReadWrite);
        errstr = m_port->errorString();
    }
    emit openMsg(ok, errstr);
    return ok;
}
cpp 复制代码
void SerialPort::close()
{
    QMutexLocker locker(&m_mutex);
    if(m_port && m_port->isOpen()) m_port->close();
}
cpp 复制代码
void SerialPort::say()
{
    qDebug()<<"SerialPort CurrrntThread = "<< QThread::currentThread();
    qDebug()<<"---------------------------------------------------------";
    QString text = "2,8,k,1,0";
    tts->say(text);
}
cpp 复制代码
void SerialPort::sendMsgSlot(QString msg)
{
    qDebug()<<"SerialPort CurrrntThread = "<< QThread::currentThread();
    qDebug()<<msg;
    qDebug()<<"---------------------------------------------------------";
}

二、使用步骤

1. 初始化C++文件和QML文件,并建立信号槽

qml中的槽函数也是定义成signal, 所以connect时,槽函数也是SIGNAL()

cpp 复制代码
serial = new SerialPort;
//serial 类向 QML 对象的上下文公开数据
ui->quickWidget_2->rootContext()->setContextProperty("serial", serial);
//根据窗口大小调整QML大小
ui->quickWidget_2->setResizeMode(QQuickWidget::SizeRootObjectToView);
// 
ui->quickWidget_2->setSource(QUrl("qrc:/Form02.qml"));
//
QObject* obj = ui->quickWidget_2->rootObject();
// 调用qml中信号或者槽函数,调用成功返回true,否则false
// 根节点,被调用信号或槽,连接方式,被调用信号或槽的参数1, 被调用信号或槽的参数2(最多10个参数)
if(QMetaObject::invokeMethod(obj, "slotOpenSerial", Qt::DirectConnection, Q_ARG(bool, true), Q_ARG(QString, "")))
    connect(serial, SIGNAL(openMsg(bool,QString)), obj, SIGNAL(slotOpenSerial(bool,QString)));

2.在qml中调用

QGroupButton 自定义的按钮组

cpp 复制代码
Item {
    id: item
    Layout.fillWidth: true
    Layout.preferredHeight: 36

    property alias checkedButton: btngroup.checkedButton

    property int btnIndexChanged: 0

    onBtnIndexChangedChanged: {
        if(btnIndexChanged == 0) {
            checkedButton = ok
        }
        else {
            checkedButton = cancle
        }
    }

    ButtonGroup {
        id: btngroup
        exclusive: true
        buttons: row.children

        onCheckedButtonChanged:
        {
            console.log("button text: ", checkedButton.text)
            btnIndexChanged = checkedButton == ok ? 0 : 1;
        }
    }

    Rectangle{
        id: rect
        anchors.fill: parent

        RowLayout {
            id: row
            anchors.fill: rect
            spacing: 6
            QButton{id: ok; text: "OK"}
            QButton{id: cancle; text: "Cancle"}
        }
    }
}
cpp 复制代码
signal slotOpenSerial(bool isOpen, string error)

onSlotOpenSerial: {
    //console.log(isOpen, error)
    if(!isOpen)
    {
        group.btnIndexChanged = 1
    }
}

qrc:/Form02.qml

cpp 复制代码
//自定义的按钮组
QGroupButton{
	id: group
	Layout.columnSpan: 2
	Layout.fillWidth: true
	onCheckedButtonChanged:
	{
		if(checkedButton.text == "OK"){
			open =  serial.open(portName.currentText, cboxBuad.currentText, dataBits.currentText,stopBits.currentText, parity.currentText, flowControl.currentText);
			console.log("serial return: ", open)
		}
		else
		{
			serial.close()
		}
	}
}

下面代码仅看这段:
QButton{
text: "1";
onClicked: {
//直接调用接口
serial.say();
//通过信号调用
serial.sendMsg("TTTT");
}
}

cpp 复制代码
Rectangle {
    Layout.columnSpan: 2
    Layout.fillWidth: true
    Layout.fillHeight: true
    color: "#156448"
    Flow {
        anchors.fill: parent
        anchors.margins: 9
        spacing: 6
        QButton{
            text: "1";
            onClicked: {
                serial.say();
                serial.sendMsg("TTTT");
            }
        }
        QButton{text: "2"}
        QButton{text: "3"}
        QButton{text: "4"}
        QButton{text: "5"}
        QButton{text: "6"}
        QButton{text: "7"}
        QButton{text: "8"}
        QButton{text: "9"}
        QButton{text: "10"}
        QButton{text: "11"}
        QButton{text: "12"}
        QButton{text: "13"}
        QButton{text: "14"}
        QButton{text: "15"}
        QButton{text: "16"}
        QButton{text: "17"}
        QButton{text: "18"}
        QButton{text: "19"}
        Rectangle {
            width:60
            height: 26
            color: "green"
            property alias text: in1.text
            onTextChanged: console.log(text)
            TextInput {
                id: in1
                anchors.fill: parent
                text: "input"
                color: "red"
                KeyNavigation.tab: in2
                selectByMouse: true
            }
        }
        Rectangle {
            width:60
            height: 26
            color: "green"
            TextInput {
                id: in2
                anchors.fill: parent
                text: "input"
                color: "red"

                KeyNavigation.tab: in1
                KeyNavigation.up: in1
            }
        }
        Loader {
            sourceComponent: testComponent
        }

    }
}

结果如图:

//---------------------------------------------------------

MainWindow CurrentThread = QThread(0x24ce850) //主线程

//---------------------------------------------------------

qml: button text: OK // 点击OK按钮打印

qml: button text: Cancle // 打开串口失败,取消OK按钮,默认Cancle按钮被点击打印

qml: serial return: false // serial.open(...)返回值打印

SerialPort CurrrntThread = QThread(0x24ce850) // serial.say() 函数运行的线程

//---------------------------------------------------------

SerialPort CurrrntThread = QThread(0xfcc9f0, name = "串口线程") // serial.sendMsg("TTTT")运行的线程

"TTTT" // 槽函数打印

//---------------------------------------------------------


相关推荐
Quz4 小时前
QML Loader:从文件加载组件、加载内联组件
qt
Quz4 小时前
QML Loader: 状态监听与动态标签页
qt
似水এ᭄往昔4 小时前
【Qt】--常用控件(显示类控件)
开发语言·qt
慧都小项8 小时前
从 Figma 到 Qt:Qtitan 能减少哪些界面还原工作?
前端·qt·嵌入式·figma·图形界面·工业界面·qtitan
用户122003879009 小时前
Qt学习之绘图入门练习
qt
西西弗Sisyphus12 小时前
Qt 实现一个 Windows 启动项查看器
开发语言·windows·qt
郝学胜-神的一滴1 天前
Qt 高级编程 045:坐标体系深度实战
开发语言·c++·windows·python·qt·程序人生
爱吃巧克力的程序媛1 天前
main.cpp注册 C++ 类到 QML 元对象系统
c++·qt
励志不掉头发的内向程序员1 天前
【LibreCAD 2D架构】从鼠标点击到图形创建:RS_ActionDrawLine交互流程与状态机解析
开发语言·c++·qt·学习·系统架构·计算机外设·交互
尘中远1 天前
给C++工业软件搭建 Agent
开发语言·c++·qt·ai·agent