示例 1:使用静态源进行直接连接

  1. 创建源对象

    要创建此 Source 对象,首先我们创建定义文件,simpleswitch.rep。此文件描述对象的属性和方法,并将其输入 Qt 远程对象编译器 repc。此文件仅定义了必须暴露给 Replicas 的接口。

    simpleswitch.rep

    class SimpleSwitch
    {
        PROP(bool currState=false);
        SLOT(server_slot(bool clientState));
    };

    simpleswitch.rep 中,

    • currState 存储开关的当前状态。
    • server_slot() 允许我们与源进行交互 - 它将连接到 echoSwitchState(bool newstate) 信号。

    对于 repc 处理此文件,请将以下行添加到您的 cmake 文件中

    qt6_add_repc_sources(directconnectserver
        simpleswitch.rep
    )

    如果您正在使用 qmake

    REPC_SOURCE = simpleswitch.rep

    这些说明仅适用于 Qt 远程对象模块,因此您还需要将其添加到项目中。如果您正在使用 CMake,请添加

    find_package(Qt6 REQUIRED COMPONENTS RemoteObjects)
    target_link_libraries(directconnectserver PRIVATE Qt6::RemoteObjects)

    如果您正在使用 qmake

    QT       += remoteobjects

    repc 在您指定的构建目录中创建了 rep_SimpleSwitch_source.h 头文件。有关更多信息,请参阅 Source

    repc 为使用 QtRO 创建了三个辅助类。对于此示例,我们使用基本类:SimpleSwitchSimpleSource。它是一个抽象类,在 rep_SimpleSwitch_source.h 中定义。我们从中派生出自定义 SimpleSwitch 实现类,如下所示

    simpleswitch.h

    #ifndef SIMPLESWITCH_H
    #define SIMPLESWITCH_H
    
    #include "rep_simpleswitch_source.h"
    
    class SimpleSwitch : public SimpleSwitchSimpleSource
    {
        Q_OBJECT
    public:
        SimpleSwitch(QObject *parent = nullptr);
        ~SimpleSwitch();
        void server_slot(bool clientState) override;
    public Q_SLOTS:
        void timeout_slot();
    private:
        QTimer *stateChangeTimer;
    };
    
    #endif

    simpleswitch.h 中,

    • stateChangeTimer 是一个 QTimer,用于切换 SimpleSwitch 的状态。
    • timeout_slot() 连接到 stateChangeTimer 的 timeout() 信号。
    • server_slot() – 当副本调用其槽的版本时在源上自动调用 – 输出接收到的值。
    • currStateChanged(bool),在由 repc 生成的 rep_SimpleSwitch_source.h 中定义,每当 currState 切换时都会发出。在此示例中,我们忽略源端的信号,稍后在副本端处理。

    我们的 SwitchState 类的定义如下所示

    simpleswitch.cpp

    #include "simpleswitch.h"
    
    // constructor
    SimpleSwitch::SimpleSwitch(QObject *parent) : SimpleSwitchSimpleSource(parent)
    {
        stateChangeTimer = new QTimer(this); // Initialize timer
        QObject::connect(stateChangeTimer, &QTimer::timeout, this, &SimpleSwitch::timeout_slot); // connect timeout() signal from stateChangeTimer to timeout_slot() of simpleSwitch
        stateChangeTimer->start(2000); // Start timer and set timout to 2 seconds
        qDebug() << "Source Node Started";
    }
    
    //destructor
    SimpleSwitch::~SimpleSwitch()
    {
        stateChangeTimer->stop();
    }
    
    void SimpleSwitch::server_slot(bool clientState)
    {
        qDebug() << "Replica state is " << clientState; // print switch state echoed back by client
    }
    
    void SimpleSwitch::timeout_slot()
    {
        // slot called on timer timeout
        if (currState()) // check if current state is true, currState() is defined in repc generated rep_simpleswitch_source.h
            setCurrState(false); // set state to false
        else
            setCurrState(true); // set state to true
        qDebug() << "Source State is "<<currState();
    
    }
  2. 创建注册表

    由于此示例使用节点之间的直接连接,因此我们可以省略此步骤。

  3. 创建主机节点

    主机节点创建如下所示

    QRemoteObjectHost srcNode(QUrl(QStringLiteral("local:replica")));
  4. 主机源对象和远程调用

    以下语句实例化了 Source 对象,并将其传递给主机以启用“远程调用”,这是使对象对 QtRO 网络可见的过程

    SimpleSwitch srcSwitch; // create simple switch
    srcNode.enableRemoting(&srcSwitch); // enable remoting

    以上步骤所实现的 main.cpp 文件内容如下

    main.cpp

    #include <QCoreApplication>
    #include "simpleswitch.h"
    
    int main(int argc, char *argv[])
    {
        QCoreApplication a(argc, argv);
    
        SimpleSwitch srcSwitch; // create simple switch
    
        // Create host node without Registry:
        QRemoteObjectHost srcNode(QUrl(QStringLiteral("local:replica")));
        srcNode.enableRemoting(&srcSwitch); // enable remoting/sharing
    
        return a.exec();
    }

    编译并运行此源端项目。在没有创建任何副本的情况下,输出应该如下所示,开关状态在每两秒内切换一次 truefalse

    "Example 1: Server Output"

以下步骤用于创建网络副本端,在这个例子中,从 获取开关状态并将其回显。

副本代码

  1. 使用 repc 向您的项目中添加副本

    我们使用与源端相同的 API 定义文件 SimpleSwitch.rep,使用 repc 创建一个 副本 头文件。如果您使用 cmake,请在客户端 cmake 文件中包含以下行,指定 .rep 文件输入

    qt6_add_repc_replicas(directconnectclient
        simpleswitch.rep
    )

    如果您使用 qmake,将以下行添加到客户端 .pro 文件中

    REPC_REPLICA = simpleswitch.rep

    repc 工具在构建目录中生成一个 rep_SimpleSwitch_replica.h 文件。有关更多信息,请参阅 副本

  2. 创建一个节点来连接到源的主节点

    以下代码实例化了网络上的第二个节点并将其连接到源主节点

    QRemoteObjectNode repNode; // create remote object node
    repNode.connectToNode(QUrl(QStringLiteral("local:replica"))); // connect with remote host node
  3. 调用节点的 acquire() 以创建一个副本的指针

    首先,我们实例化一个副本

    QSharedPointer<SimpleSwitchReplica> ptr;
    ptr.reset(repNode.acquire<SimpleSwitchReplica>()); // acquire replica of source from host node

    注意:acquire() 返回一个指向副本的指针,但不管理其生命周期。此示例展示了将返回的指针包裹在 QSharedPointerQScopedPointer 中的建议流程,以确保总是正确删除指针。

    main.cpp 实现了上述步骤并实例化了我们的对象

    main.cpp

    #include <QCoreApplication>
    #include "client.h"
    
    int main(int argc, char *argv[])
    {
        QCoreApplication a(argc, argv);
    
        QSharedPointer<SimpleSwitchReplica> ptr; // shared pointer to hold source replica
    
        QRemoteObjectNode repNode; // create remote object node
        repNode.connectToNode(QUrl(QStringLiteral("local:replica"))); // connect with remote host node
    
        ptr.reset(repNode.acquire<SimpleSwitchReplica>()); // acquire replica of source from host node
    
        Client rswitch(ptr); // create client switch object and pass reference of replica to it
    
        return a.exec();
    }

    Client 类的完整声明和定义如下

    client.h

    #ifndef _CLIENT_H
    #define _CLIENT_H
    
    #include <QObject>
    #include <QSharedPointer>
    
    #include "rep_simpleswitch_replica.h"
    
    class Client : public QObject
    {
        Q_OBJECT
    public:
        Client(QSharedPointer<SimpleSwitchReplica> ptr);
        ~Client() override = default;
        void initConnections();// Function to connect signals and slots of source and client
    
    Q_SIGNALS:
        void echoSwitchState(bool switchState);// this signal is connected with server_slot(..) on the source object and echoes back switch state received from source
    
    public Q_SLOTS:
        void recSwitchState_slot(bool); // slot to receive source state
    private:
        bool clientSwitchState; // holds received server switch state
        QSharedPointer<SimpleSwitchReplica> reptr;// holds reference to replica
    
     };
    
    #endif

    client.cpp

    #include "client.h"
    
    // constructor
    Client::Client(QSharedPointer<SimpleSwitchReplica> ptr) :
        QObject(nullptr),reptr(ptr)
    {
        // Connect signal for replica initialized with initialization slot.
        initConnections();
        // We can connect to SimpleSwitchReplica Signals/Slots
        // directly because our Replica was generated by repc.
    }
    
    void Client::initConnections()
    {
        // initialize connections between signals and slots
    
        // connect source replica signal currStateChanged() with client's recSwitchState() slot to receive source's current state
        QObject::connect(reptr.data(), &SimpleSwitchReplica::currStateChanged, this, &Client::recSwitchState_slot);
        // connect client's echoSwitchState(..) signal with replica's server_slot(..) to echo back received state
        QObject::connect(this, &Client::echoSwitchState, reptr.data(), &SimpleSwitchReplica::server_slot);
    }
    
    void Client::recSwitchState_slot(bool value)
    {
        qDebug() << "Received source state "<< value << reptr.data()->currState();
        clientSwitchState = reptr.data()->currState();
        Q_EMIT echoSwitchState(clientSwitchState); // Emit signal to echo received state back to server
    }

    编译并运行此示例,连同源端示例一起生成以下输出

    "Direct Connect Server Client Communication output"

© 2024 The Qt Company Ltd. 本文档内的文档贡献是它们各自所有者的版权。本提供的文档根据 Free Software Foundation 发布的 GNU Free Documentation License 1.3 版本 的条款许可。Qt 及相关标志是 The Qt Company Ltd. 在芬兰及和/或全球其他国家的商标。所有其他商标归其各自所有者所有。