Q_INVOKABLE
是一个Qt元对象系统中的宏,用于将C++函数暴露给QML引擎。具体来说,它使得在QML代码中可以直接调用C++类中被标记为Q_INVOKABLE的成员函数。
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;
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();
QStringList SerialPort::availablePorts()
{
QStringList list;
foreach(auto info, QSerialPortInfo::availablePorts()) list.append(info.portName());
list<<"COM11"<<"COM22";
return list;
}
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;
}
void SerialPort::close()
{
QMutexLocker locker(&m_mutex);
if(m_port && m_port->isOpen()) m_port->close();
}
void SerialPort::say()
{
qDebug()<<"SerialPort CurrrntThread = "<< QThread::currentThread();
qDebug()<<"---------------------------------------------------------";
QString text = "2,8,k,1,0";
tts->say(text);
}
void SerialPort::sendMsgSlot(QString msg)
{
qDebug()<<"SerialPort CurrrntThread = "<< QThread::currentThread();
qDebug()<<msg;
qDebug()<<"---------------------------------------------------------";
}
qml中的槽函数也是定义成signal, 所以connect时,槽函数也是SIGNAL()
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)));
QGroupButton 自定义的按钮组
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"}
}
}
}
signal slotOpenSerial(bool isOpen, string error)
onSlotOpenSerial: {
//console.log(isOpen, error)
if(!isOpen)
{
group.btnIndexChanged = 1
}
}
qrc:/Form02.qml
//自定义的按钮组
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");
}
}
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” // 槽函数打印
//---------------------------------------------------------