QT_dbus(ipc进程间通讯)

news2024/11/26 13:40:07

QT_dbus(ipc进程间通讯)

前言:
参考链接:
https://www.cnblogs.com/brt3/p/9614899.html
https://blog.csdn.net/weixin_43246170/article/details/120994311
https://blog.csdn.net/kchmmd/article/details/118605315
一个大型项目可能需要多个子程序同时运行,但是子程序之间的通讯就需要进程间通讯,DBUS是QT自带的组件,尝试使用一下。

1、创建包含多个子程序的工程
在这里插入图片描述
在这里插入图片描述

TEMPLATE = subdirs

在这里插入图片描述

2、第一个dbus试验:先建立session bus的连接,然后使用QT自带工具qdbusviewer演示使用
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

#include "mainwidget.h"
#include "qdebug.h"
#include "dbus/RPCClient.h"
#include "dbus/DBUSServer.h"
#include "dbus/MessageTip.h"
#include <QProcess>

#include <QtDBus/QtDBus>
#include <QDBusError>

MainWidget::MainWidget()
{
    QQmlApplicationEngine *m_pEngine = new QQmlApplicationEngine;
    QQmlComponent component(m_pEngine, QUrl(QStringLiteral("qrc:/main.qml")));
    QObject *mainObject = component.create();
    if (mainObject == nullptr) {
        qDebug() << "mainObject fail";
        return;
    }

    // 用于建立到session bus的连接
    QDBusConnection bus = QDBusConnection::sessionBus();

    // 在session bus上注册名为"com.test.hotel"的service
    if (!bus.registerService("com.test.hotel")) {
        qDebug() << bus.lastError().message();
        exit(1);
    }

    //一定要用实例化这种形式,使用定义的方式不行
    DBUSServer *dbusserver = new DBUSServer();
    // 注册名为"/dbusserver"的object。
    // "QDBusConnection::ExportAllSlots"表示把类DBUSServer的所有Slot都导出为这个Object的method
    bus.registerObject("/dbusserver", dbusserver, QDBusConnection::ExportAllSlots);
    //bus.registerObject("/dbusserver", dbusserver, QDBusConnection::ExportAllSignal);
}

DBUSServer.cpp

#include "DBUSServer.h"
#include "qdebug.h"

DBUSServer::DBUSServer()
{
    connect(this, SIGNAL(opendoor()), this, SLOT(onopenlight()));
}

void DBUSServer::oncheckIn()
{
    qDebug() << "checkIn";
    emit opendoor();
}
void DBUSServer::oncheckOut()
{
    qDebug() << "oncheckOut";
}
void DBUSServer::onopenlight()
{
    qDebug() << "onopenlight";
}
int DBUSServer::onquery()
{
    return 50;
}

DBUSServer.h

#ifndef DBUSSERVER_H
#define DBUSSERVER_H
#include <QObject>
#include <QBrush>
class DBUSServer : public QObject
{
    Q_OBJECT
public:
    DBUSServer();

public slots:
    void oncheckIn();
    void oncheckOut();
    int onquery();
    void onopenlight();

signals:
    // Check in,参数为房间数,返回成功拿到的房间数
    void opendoor();

private:
    int m_rooms;
    //QReadWriteLock m_lock;

};
#endif // RPCSERVER_H

3、综合试验,经过几天的研究,决定以后采用下面的方法来进行进程间通讯
方法一:
说明:类似信号和槽(我个人认为是类似于MQTT协议的订阅和发布机制),

//函数说明:在不同进程之间建立信号和槽的关系,"on_hello"是自定义的信号的名(也可认为是发布的主题)
//参数1:服务器地址,参数2:路径(不填),参数3:Interface名称(不填),参数4:自定义信号(可认为是订阅信号),参数5:槽函数所在的对象,参数6:槽函数
QDBusConnection::sessionBus().connect("com.test.hotel", "", "", "on_hello", this, SLOT(onApplyvalueChanged(int)));

//函数说明:真正发布消息的地方,只要是和"on_hello"建立连接的槽函数都会得到相应
QDBusMessage msg = QDBusMessage::createSignal("/dbusserver", "com.test.hotel", "on_hello");
msg << 456;  //如果带参数就这样加上要传的参数
QDBusConnection::sessionBus().send(msg);

方法二:
说明:这种方法虽然思路清晰,但是调用一次函数代码量比较多,不是太推荐

//参数1:服务器地址,参数2:路径,参数3:Interface名称,参数4:调用槽函数的名字
QDBusMessage message = QDBusMessage::createMethodCall("com.test.hotel",
                       "/dbusserver",
                       "com.test.hotel.show",
                       "oncheckIn");
//槽函数有几种情况:①有参数传入无参数返回,②有参数传入有参数返回,③无参数传入有参数返回
/*****************有参数传入有参数返回*****************/
message << 123;//给int oncheckIn(int value);这个槽函数传入的参数(如果没有参数需要传,此步骤不用写)
//发送消息并获取返回值
QDBusMessage response = QDBusConnection::sessionBus().call(message);
//判断method是否被正确返回
if (response.type() == QDBusMessage::ReplyMessage) 
{
    //从返回参数获取返回值
    int value = response.arguments().takeFirst().toInt();
    qDebug() << QString("value =  %1").arg(value);
} 
else 
{
    qDebug() << "value method called failed!";
}

/*****************有参数传入无参数返回*****************/
message << 123;//给int oncheckIn(int value);这个槽函数传入的参数(如果没有参数需要传,此步骤不用写)
//发送消息
QDBusMessage response = QDBusConnection::sessionBus().call(message);
//判断method是否被正确返回
if (response.type() == QDBusMessage::ReplyMessage) 
{
    qDebug() << "value method called successfull";
} 
else 
{
    qDebug() << "value method called failed!";
}

/*****************无参数传入无参数返回*****************/
//发送消息
QDBusMessage response = QDBusConnection::sessionBus().call(message);
//判断method是否被正确返回
if (response.type() == QDBusMessage::ReplyMessage) 
{
    qDebug() << "value method called successfull";
} 
else 
{
    qDebug() << "value method called failed!";
}

方法三:
说明:这种方法虽然思路清晰,比方法二更简介一些,推荐使用

//参数1:服务器地址,参数2:路径,参数3:Interface名称
QDBusInterface interface("com.test.hotel", "/dbusserver", "com.test.hotel.show", QDBusConnection::sessionBus());
if (!interface.isValid()) {
    qDebug() << "dbus interface fail";
    return;
}
QDBusMessage response;
//调用槽函数分为三种:①有参数传入无参数返回,②有参数传入有参数返回,③无参数传入有参数返回
//response = interface.call("onquery", 158);//有参数传入有参数返回
response = interface.call("onquery");//无参数传入有参数返回/有参数传入无参数返回
//判断method是否被正确返回
if (response.type() == QDBusMessage::ReplyMessage) {
    //从返回参数获取返回值(没有返回值的返回0,有返回值的正常返回)
    int value = response.arguments().takeFirst().toInt();
    qDebug() << QString("value =  %1").arg(value);
} 
else 
{
    qDebug() << "value method called failed!";
}

工程源码展示:
在这里插入图片描述

test_rpc.pro

TEMPLATE = subdirs

SUBDIRS += \
    apply \
    layer

apply/apply.pro

QT += quick \
    widgets \
    dbus

CONFIG += c++11

# The following define makes your compiler emit warnings if you use
# any Qt feature that has been marked deprecated (the exact warnings
# depend on your compiler). Refer to the documentation for the
# deprecated API to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS

# You can also make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0

SOURCES += \
        Dbusclass.cpp \
        main.cpp \
        mainwidget.cpp

RESOURCES += qml.qrc

# Additional import path used to resolve QML modules in Qt Creator's code model
QML_IMPORT_PATH =

# Additional import path used to resolve QML modules just for Qt Quick Designer
QML_DESIGNER_IMPORT_PATH =

# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target

HEADERS += \
    Dbusclass.h \
    mainwidget.h

apply/Headers/Dbusclass.h

#ifndef DBUSCLASS_H
#define DBUSCLASS_H
#include <QObject>
#include <QBrush>
class Dbusclass : public QObject
{
    Q_OBJECT
    //定义Interface名称为:"com.test.hotel.show"
    Q_CLASSINFO("D-Bus Interface", "com.test.apply.show")
public:
    Dbusclass();

public slots:
    int oncheckIn(int value);//有参数传入有参数返回
    void oncheckOut(int value);//有参数传入无参数返回
    int onquery();//无参数传入有参数返回
    void onopenlight();//无参数传入无参数返回

signals:
    void opendoor();

private:
    int m_rooms;
};
#endif // RPCSERVER_H

apply/Headers/mainwidget.h

#ifndef MAINWIDGET_H
#define MAINWIDGET_H

#include <QObject>
#include <QWidget>
#include <QQmlComponent>
#include <QQmlApplicationEngine>
#include <QQuickItem>
#include "Dbusclass.h"

class MainWidget : public QObject
{
    Q_OBJECT

public:
    MainWidget();

protected slots:
    void onClickPageNo(bool enable);
    void onApplyvalueChanged(int value);
    void onApplystringChanged(QString value);

    void oncreateSignal();
    void onqDBusMessage();
    void onqDBusInterface();

private:
    QQuickItem *m_applyItem = nullptr;
    QObject *m_applyObject = nullptr;
};

#endif // MAINWIDGET_H

apply/Sources/Dbusclass.cpp

#include "Dbusclass.h"
#include "qdebug.h"
#include <QDebug>

Dbusclass::Dbusclass()
{
    connect(this, SIGNAL(opendoor()), this, SLOT(onopenlight()));
}

int Dbusclass::oncheckIn(int value)
{
    qDebug() << "checkIn:" << value;
    emit opendoor();
    return value;
}
void Dbusclass::oncheckOut(int value)
{
    qDebug() << "oncheckOut:" << value;
}
void Dbusclass::onopenlight()
{
    qDebug() << "onopenlight";
}
int Dbusclass::onquery()
{
    return 50;
}

apply/Sources/mainwidget.cpp

#include "mainwidget.h"
#include "qdebug.h"
#include "Dbusclass.h"
#include <QProcess>

#include <QtDBus/QtDBus>
#include <QDBusError>
#include <QDBusMessage>

MainWidget::MainWidget()
{
    QQmlApplicationEngine *m_pEngine = new QQmlApplicationEngine;
    QQmlComponent component(m_pEngine, QUrl(QStringLiteral("qrc:/main.qml")));
    QObject *mainObject = component.create();
    if (mainObject == nullptr) {
        qDebug() << "mainObject fail";
        return;
    }

    QList<QObject *> objectList = mainObject->findChildren<QObject *>("mybutton");
    if (objectList.isEmpty()) {
        qDebug() << "mybutton failed\n";
        return;
    }
    m_applyObject = objectList.last();

    connect(m_applyObject, SIGNAL(applyvalueChanged(int)), this, SLOT(onApplyvalueChanged(int)));
    connect(m_applyObject, SIGNAL(applystringChanged(QString)), this, SLOT(onApplystringChanged(QString)));
    connect(mainObject, SIGNAL(window_interface(bool)), this, SLOT(onClickPageNo(bool)));
    connect(mainObject, SIGNAL(createSignal()), this, SLOT(oncreateSignal()));
    connect(mainObject, SIGNAL(qDBusMessage()), this, SLOT(onqDBusMessage()));
    connect(mainObject, SIGNAL(qDBusInterface()), this, SLOT(onqDBusInterface()));

    // 用于建立到session bus的连接
    QDBusConnection bus = QDBusConnection::sessionBus();

    // 在session bus上注册名为"com.test.hotel"的service
    if (!bus.registerService("com.test.apply")) {
        qDebug() << bus.lastError().message();
        exit(1);
    }

    //一定要用实例化这种形式,使用定义的方式不行
    Dbusclass *dbusapply = new Dbusclass();
    // 注册名为"/dbusserver"的object。
    // "QDBusConnection::ExportAllSlots"表示把类DBUSServer的所有Slot都导出为这个Object的method
    bus.registerObject("/dbusapply", dbusapply, QDBusConnection::ExportAllSlots);
    //bus.registerObject("/dbusapply", dbusapply, QDBusConnection::ExportAllSignal);

    //参数1:服务器地址,参数2:路径,参数3:Interface名称(不填),参数4:自定义信号(可认为是订阅信号),参数5:槽函数所在的对象,参数6:槽函数
    QDBusConnection::sessionBus().connect("com.test.layer", "", "", "on_layer", this, SLOT(onApplyvalueChanged(int)));
}

void MainWidget::onClickPageNo(bool enable)
{
    //打开子程序
    QProcess *process = new QProcess();
    process->start("/home/zhou/work/test/build-test_rpc-Desktop_Qt_5_14_2_GCC_64bit-Debug/layer/layer");
}

void MainWidget::onApplyvalueChanged(int value)
{
    qDebug() << "onApplyvalueChanged" << value;
}

void MainWidget::onApplystringChanged(QString value)
{
    qDebug() << "onApplystringChanged" << value;
}

void MainWidget::oncreateSignal()
{
    qDebug() << "oncreateSignal" ;
    QDBusMessage msg = QDBusMessage::createSignal("/dbuslayer", "com.test.layer.show", "on_apply");
    msg << 456;
    QDBusConnection::sessionBus().send(msg);
}

void MainWidget::onqDBusMessage()
{
    qDebug() << "onqDBusMessage" ;

    QDBusMessage message = QDBusMessage::createMethodCall("com.test.layer",
                           "/dbuslayer",
                           "com.test.layer.show",
                           "oncheckIn");
    message << 234;
    //发送消息
    QDBusMessage response = QDBusConnection::sessionBus().call(message);

    //判断method是否被正确返回
    if (response.type() == QDBusMessage::ReplyMessage) {
        //从返回参数获取返回值
        int value = response.arguments().takeFirst().toInt();
        qDebug() << QString("value =  %1").arg(value);
    } else {
        qDebug() << "value method called failed!";
    }
}

void MainWidget::onqDBusInterface()
{
    qDebug() << "onqDBusInterface" ;

    QDBusInterface interface("com.test.layer", "/dbuslayer", "com.test.layer.show", QDBusConnection::sessionBus());
    if (!interface.isValid()) {
        qDebug() << "dbus interface fail";
        return;
    }
    QDBusMessage response;
    response = interface.call("oncheckIn", 158);    // 有参数
    //判断method是否被正确返回
    if (response.type() == QDBusMessage::ReplyMessage) {
        //从返回参数获取返回值
        int value = response.arguments().takeFirst().toInt();
        qDebug() << QString("value =  %1").arg(value);
    } else {
        qDebug() << "value method called failed!";
    }
}

apply/Sources/main.cpp

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include "mainwidget.h"
#include "qdebug.h"
#include "qthread.h"

int main(int argc, char *argv[])
{
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);

    QGuiApplication app(argc, argv);

//    QQmlApplicationEngine engine;
//    const QUrl url(QStringLiteral("qrc:/main.qml"));
//    QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
//    &app, [url](QObject * obj, const QUrl & objUrl) {
//        if (!obj && url == objUrl) {
//            QCoreApplication::exit(-1);
//        }
//    }, Qt::QueuedConnection);
//    engine.load(url);

    MainWidget mainwidget;
    return app.exec();
}

apply/main.qml

import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.12

Window {
    visible: true
    width: 640
    height: 480
    objectName: "apply_window"
    title: qsTr("Hello apply")

    signal window_interface(bool enable)
    signal createSignal()
    signal qDBusMessage()
    signal qDBusInterface()

    Column{
        anchors.fill: parent
        spacing: 20
        Button{
            width: 140
            height: 50

            text: "开启界面2"
            onClicked: {
                window_interface(true)
            }
        }

        Button{
            width: 140
            height: 50

            text: "createSignal_发布消息"
            onClicked: {
                createSignal()
            }
        }

        Button{
            width: 140
            height: 50

            text: "QDBusMessage"
            onClicked: {
                qDBusMessage()
            }
        }

        Button{
            width: 140
            height: 50

            text: "QDBusInterface"
            onClicked: {
                qDBusInterface()
            }
        }

        Mybutton{
            width: 140
            height: 300
        }
    }
}

apply/Mybutton.qml

import QtQuick 2.0
import QtQuick.Controls 2.12

Item {
    objectName: "mybutton"

    signal applyvalueChanged(int value)
    signal applystringChanged(string value)

    Column{
        spacing: 10
        Button{
            objectName: "button"
            width: 140
            height: 50

            text: "send1"

            onClicked: {
                applyvalueChanged(1)
            }
        }
        Button{
            width: 140
            height: 50

            text: "send2"

            onClicked: {
                applyvalueChanged(2)
            }
        }
        Button{
            width: 140
            height: 50

            text: "验证string"
            onClicked: {
                applystringChanged("{\"name\":\"lili\",\"age\":24,\"class\":6}")
            }
        }
    }
}

layer.pro

QT += quick
QT += widgets
QT += dbus

CONFIG += c++11

# The following define makes your compiler emit warnings if you use
# any Qt feature that has been marked deprecated (the exact warnings
# depend on your compiler). Refer to the documentation for the
# deprecated API to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS

# You can also make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0

SOURCES += \
        dbusclass.cpp \
        main.cpp \
        mainwidget.cpp

RESOURCES += qml.qrc

# Additional import path used to resolve QML modules in Qt Creator's code model
QML_IMPORT_PATH =

# Additional import path used to resolve QML modules just for Qt Quick Designer
QML_DESIGNER_IMPORT_PATH =

# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target

HEADERS += \
    dbusclass.h \
    mainwidget.h

layer/Herders/dbusclass.h

#ifndef DBUSCLASS_H
#define DBUSCLASS_H

#include <QObject>

class Dbusclass : public QObject
{
    Q_OBJECT
    //定义Interface名称为:"com.test.layer.show"
    Q_CLASSINFO("D-Bus Interface", "com.test.layer.show")
public:
    Dbusclass();

public slots:
    int oncheckIn(int value);//有参数传入有参数返回
};

#endif // DBUSCLASS_H

layer/Herders/mainwidget.h

#ifndef MAINWIDGET_H
#define MAINWIDGET_H

#include <QObject>
#include <QQmlComponent>
#include <QQmlApplicationEngine>
#include <QQuickItem>

class mainwidget : public QObject
{
    Q_OBJECT
public:
    mainwidget();

public slots:
    void oncreateSignal();
    void onqDBusMessage();
    void onqDBusInterface();
    void onMessage_recv(int num);

private:
};

#endif // MAINWIDGET_H

layer/Sources/dbusclass.cpp

#include "dbusclass.h"
#include <QDebug>

Dbusclass::Dbusclass()
{

}

int Dbusclass::oncheckIn(int value)
{
    qDebug() << "checkIn:" << value;
    return value;
}

layer/Sources/mainwidget.cpp

#include "mainwidget.h"
#include "dbusclass.h"
#include <QDBusMessage>
#include <QDBusConnection>
#include <QDBusInterface>
#include <QtDBus/QtDBus>


mainwidget::mainwidget()
{
    QQmlApplicationEngine *m_pEngine = new QQmlApplicationEngine;
    QQmlComponent component(m_pEngine, QUrl(QStringLiteral("qrc:/main.qml")));
    QObject *mainObject = component.create();
    if (mainObject == nullptr) {
        qDebug() << "mainObject fail";
        return;
    }

    // 用于建立到session bus的连接
    QDBusConnection bus = QDBusConnection::sessionBus();

    // 在session bus上注册名为"com.test.hotel"的service
    if (!bus.registerService("com.test.layer")) {
        qDebug() << bus.lastError().message();
        exit(1);
    }

    //一定要用实例化这种形式,使用定义的方式不行
    Dbusclass *dbusclass = new Dbusclass();
    // 注册名为"/dbuslayer"的object。
    // "QDBusConnection::ExportAllSlots"表示把类DBUSServer的所有Slot都导出为这个Object的method
    bus.registerObject("/dbuslayer", dbusclass, QDBusConnection::ExportAllSlots);

    connect(mainObject, SIGNAL(createSignal()), this, SLOT(oncreateSignal()));
    connect(mainObject, SIGNAL(qDBusMessage()), this, SLOT(onqDBusMessage()));
    connect(mainObject, SIGNAL(qDBusInterface()), this, SLOT(onqDBusInterface()));

    QDBusConnection::sessionBus().connect("com.test.apply", "", "", "on_apply", this, SLOT(onMessage_recv(int)));
}

void mainwidget::oncreateSignal()
{
    qDebug() << "oncreateSignal";

    QDBusMessage msg = QDBusMessage::createSignal("/dbusapply", "com.test.apply.show", "on_layer");
    msg << 123;
    QDBusConnection::sessionBus().send(msg);
}

void mainwidget::onqDBusMessage()
{
    qDebug() << "onLayer_reduce";

    QDBusMessage message = QDBusMessage::createMethodCall("com.test.apply",
                           "/dbusapply",
                           "com.test.apply.show",
                           "oncheckIn");
    message << 234;
    //发送消息
    QDBusMessage response = QDBusConnection::sessionBus().call(message);

    //判断method是否被正确返回
    if (response.type() == QDBusMessage::ReplyMessage) {
        //从返回参数获取返回值
        int value = response.arguments().takeFirst().toInt();
        qDebug() << QString("value =  %1").arg(value);
    } else {
        qDebug() << "value method called failed!";
    }
}

void mainwidget::onqDBusInterface()
{
    qDebug() << "onLayer_reduce";

    QDBusInterface interface("com.test.apply", "/dbusapply", "com.test.apply.show", QDBusConnection::sessionBus());
    if (!interface.isValid()) {
        qDebug() << "dbus interface fail";
        return;
    }
    QDBusMessage response;
    response = interface.call("oncheckIn", 158);    // 有参数
//    response = interface.call("oncheckOut");    // 无参数
//    response = interface.call("onopenlight");
    //判断method是否被正确返回
    if (response.type() == QDBusMessage::ReplyMessage) {
        //从返回参数获取返回值
        int value = response.arguments().takeFirst().toInt();
        qDebug() << QString("value =  %1").arg(value);
    } else {
        qDebug() << "value method called failed!";
    }
}

void mainwidget::onMessage_recv(int num)
{
    qDebug() << "onMessage_recv:" << num;
}

layer/Sources/main.cpp

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include "qdebug.h"
#include "mainwidget.h"

int main(int argc, char *argv[])
{
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);

    QGuiApplication app(argc, argv);

//    QQmlApplicationEngine engine;
//    const QUrl url(QStringLiteral("qrc:/main.qml"));
//    QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
//    &app, [url](QObject * obj, const QUrl & objUrl) {
//        if (!obj && url == objUrl) {
//            QCoreApplication::exit(-1);
//        }
//    }, Qt::QueuedConnection);
//    engine.load(url);

    mainwidget mainwidget;

    return app.exec();
}

layer/main.qml

import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.12

Window {
    visible: true
    width: 640
    height: 480
    title: qsTr("Hello layer")

    signal createSignal()
    signal qDBusMessage()
    signal qDBusInterface()

    Column{
        anchors.fill: parent
        spacing: 20

        Button{
            width: 140
            height: 50

            text: "createSignal_发布消息"
            onClicked: {
                createSignal()
            }
        }

        Button{
            width: 140
            height: 50

            text: "QDBusMessage"
            onClicked: {
                qDBusMessage()
            }
        }

        Button{
            width: 140
            height: 50

            text: "QDBusInterface"
            onClicked: {
                qDBusInterface()
            }
        }
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/364954.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

《计算机网络:自顶向下方法》实验5:ARP协议分析 Wireshark实验

实验13:ARP协议分析 1 What is the 48-bit Ethernet address of your computer? 00:d0:59:a9:3d:68 2 What is the 48-bit destination address in the Ethernet frame? Is this the Ethernet address of gaia.cs.umass.edu? (Hint: the answer is no). What device has …

推荐算法—widedeep原理知识总结代码实现

wide&deep原理知识总结代码实现1. Wide&Deep 模型的结构1.1 模型的记忆能力1.2 模型的泛化能力2. Wide&Deep 模型的应用场景3. Wide&Deep 模型的代码实现3.1 tensorflow实现3.2 pytorch实现今天&#xff0c;总结一个在业界有着巨大影响力的推荐模型&#xff0c…

设计模式.工厂模式.黑马跟学笔记

设计模式.工厂模式4.创建型模式4.2 工厂模式4.2.1 概述4.2.2 简单工厂模式4.2.2.1 结构4.2.2.2 实现4.2.2.4 优缺点4.2.2.3 扩展4.2.3 工厂方法模式4.2.3.1 概念4.2.3.2 结构4.2.3.3 实现4.2.3.4 优缺点4.2.4 抽象工厂模式4.2.4.1 概念4.2.4.2 结构4.2.4.2 实现4.2.4.3 优缺点4…

C语言进阶(六)—— 结构体

1. 结构体基础知识1.1 结构体类型的定义struct Person{char name[64];int age; };typedef struct _PERSON{char name[64];int age; }Person;注意&#xff1a;定义结构体类型时不要直接给成员赋值&#xff0c;结构体只是一个类型&#xff0c;编译器还没有为其分配空间&#xff0…

【Kubernetes 入门实战课】Day02——初识容器

系列文章目录 【Kubernetes 入门实战课】Day01——搭建kubernetes实验环境(一) 文章目录系列文章目录前言一、Docker的诞生二、Docker的形态1、Docker Desktop2、Docker Engine二、Docker的安装1、服务器连接外网安装2、服务器不通外网三、Docker的使用三、Docker的架构总结前…

JavaWeb11-死锁

目录 1.死锁定义 1.1.代码演示 1.2.使用jconsole/jvisualvm/jmc查看死锁 ①使用jconsole&#xff1a;最简单。 ②使用jvisualvm&#xff1a;&#xff08;Java虚拟机&#xff09;更方便&#xff0c;更直观&#xff0c;更智能&#xff0c;更高级&#xff0c;是合适的选择。 …

Melis4.0[D1s]:2.启动流程(GUI桌面加载部分)跟踪笔记

文章目录0. 控制台输出信息等级设置0.1 设置log level 4 无法正常启动1.宏观启动流程1.1 控制台入口函数finsh_thread_entry()执行《startup.sh》1.2 《startup.sh》启动桌面GUI模块1.2.1 《startup.sh》加载 desktop.mod1.2.2 desktop.mod加载 init.axf1.2.3 init.axf 介绍1.…

C#与三菱PLC MC协议通信,Java与三菱PLC MC协议通信

三菱PLC的MC协议是一种常用的通信协议&#xff0c;用于实现三菱PLC与其他设备之间的通信。以下是一些关于MC协议的基本信息&#xff1a;协议格式MC协议的通信数据格式如下&#xff1a;数据头网络编号PC编号目标模块IO编号目标模块站号本机模块IO编号本机模块站号请求数据长度请…

Linud SSH与SCP的配置

目录 配置SSH协议 配置服务器通过密钥进行认证 配置SCP完成文件传输 ssh协议讲解 SSH协议理论讲解_静下心来敲木鱼的博客-CSDN博客https://blog.csdn.net/m0_49864110/article/details/128500490?ops_request_misc%257B%2522request%255Fid%2522%253A%2522167704203816800…

不加大资金投入,仅凭智能名片如何解决企业营销难题的?

中国90%以上的中小企业想要竞争和发展&#xff0c;就必须推广自己的品牌&#xff0c;提高自己的知名度。在小程序之前&#xff0c;APP是主流&#xff0c;但大多数中小企业负担不起APP的开发和昂贵的营销成本。 进入微信互联网时代后&#xff0c;为了帮助企业以更低的成本获得…

浙大MEM现场小组复试经验分享

作为2019年上岸浙大MEM项目的学姐一枚&#xff0c;很高兴收到杭州达立易考教育老师的邀请&#xff0c;给大家分享下现场面试的经历。先来看下复试流程是怎么样的。1、体检所有考生须参加。体检需在复试前完成&#xff08;未体检考生不得参加复试&#xff09;。 2、资格审查&…

历时半年!从外包到现在阿里网易25K,分享一下自己的涨薪经验

前言 首先自我介绍一下&#xff0c;本人普通一本毕业&#xff0c;年初被老东家裁员干掉了&#xff0c;之后一直住在朋友那混吃等死&#xff0c;转折是今年年后&#xff0c;二月初的时候和大佬吃了个饭&#xff0c;觉得自己不能这样下去了&#xff0c;拿着某大佬给我的面试资料…

你知道IT运维的本质是什么吗?

大家好&#xff0c;我是技福的小咖老师。 之前看到个文章&#xff0c;说运维的本质是“可视化”&#xff0c;甚至还有人说是DevOps。不可否认&#xff0c;“可视化”是运维过程中非常重要的一个环节&#xff1b;DevOps则是开发运维一体化非常重要的工具。 究其根本&#xff0…

【09-JVM面试专题-实例化过程详细讲讲?对象的基本结构你知道吗?TLAB堆上内存分配是怎么样的?你了解这个TLAB吗?】

实例化过程详细讲讲&#xff1f;对象的基本结构你知道吗&#xff1f;TLAB堆上内存分配是怎么样的&#xff1f;你了解这个TLAB吗&#xff1f; 实例化过程详细讲讲&#xff1f;对象的基本结构你知道吗&#xff1f;TLAB堆上内存分配是怎么样的&#xff1f;你了解这个TLAB吗&#x…

EMR Studio Workspace 访问 Github ( 公网Git仓库 )

EMR Studio Workspace访问公网Git仓库 会遇到很多问题,由于EMR Studio不能给出任何有用的错误信息,导致排查起来非常麻烦。下面总结了若干项注意事项,可以避免踩坑。如果你遇到了同样的问题,请根据以下部分或全部建议去修正你的环境,问题即可解决。本文地址:https://laur…

pc端集成企业微信的扫码登录及遇到的问题

集成步骤&#xff1a; 1、在企业微信后台中添加应用 2、记录下应用的相关信息&#xff0c;在后文要用到 3、引入企业微信js 旧版&#xff1a;http://rescdn.qqmail.com/node/ww/wwopenmng/js/sso/wwLogin-1.0.0.js 新版&#xff08;20210803更新&#xff09;&#xff1a;http…

kotlin学习教程

kotlin的方法 可以直接调用 不用 new? 2.kotlin关于字符串 用 $拼接变量 3.kotlin 类 方法 变量 可以同级的&#xff0c;同级的 方法 和 变量(常量) 是 生成了 一个新的 xxxKt.class &#xff0c;并且都是 static的&#xff0c; 4.kotlin的类&#xff0c;方法&#xff0c;默认…

JVM调优方式

对JVM内存的系统级的调优主要的目的是减少GC的频率和Full GC的次数。 1.Full GC 会对整个堆进行整理&#xff0c;包括Young、Tenured和Perm。Full GC因为需要对整个堆进行回收&#xff0c;所以比较慢&#xff0c;因此应该尽可能减少Full GC的次数。 2.导致Full GC的原因 1)年老…

消息中间件

为什么要使用消息中间件同步通信&#xff1a;耗时长&#xff0c;受网络波动影响&#xff0c;不能保证高成功率&#xff0c;耦合性高。1.同步方式&#xff08;耗时长&#xff09;&#xff1a;同步方式的问题&#xff1a;当一个用户提交订单到成功需要300ms300ms300ms20ms 920ms…

民锋国际期货:2023,既艰难又充满希望,既纷乱又有无数机会。

不管是官方还是民间&#xff0c;各种信号都表明&#xff0c;2023年是一个拼经济的年份。 通货膨胀带来的需求量的增加&#xff0c;与中国经济高速发展带来的供给量增加&#xff0c;二者共同构成了我们的物价。 做一个长期主义者&#xff0c;做一个坚定看好中国未来的人&#…