This section contains snippets that were automatically translated from C++ to Python and may contain errors.
Example 1: Direct Connection using a Static Source#
Describes how the Qt Remote Objects establishes a direct connection using a static source. .. _qtro-example1: In this example, the source object is a simple binary switch that toggles its state based on a timer. When the state changes, a signal is emitted by the source which QtRO propagates to all replicas. Since the replicas have the same properties, signals, and slots as were exposed from the source, any slots connected to the replica’s signal will be called when the replica receives that signal. The client process then echoes back the received switch state to the source by emitting its own signal which is connected to a slot on the replica.
Create a source object
To create this Source object, first we create the definition file,
simpleswitch.rep. This file describes the properties and methods for the object and is input to the Qt Remote Objects Compiler repc . This file only defines interfaces that are necessary to expose to the Replicas .
simpleswitch.repclass SimpleSwitch(): PROP(bool currState=False) SLOT(server_slot(bool clientState))
currStateholds the current state of the switch.
server_slot()allows us to interact with the source - it will be connected to the
For repc to process this file, add the following line to your
cmakefile:qt6_add_repc_sources(directconnectserver simpleswitch.rep )
If you’re using
qmake:REPC_SOURCE = simpleswitch.rep
These instructions are only relevant for the Qt Remote Object module, so you need to add it to your project as well. If you’re using CMake, add:find_package(Qt6 REQUIRED COMPONENTS RemoteObjects) target_link_libraries(directconnectserver PRIVATE Qt6::RemoteObjects)
If you’re using
qmake:QT += remoteobjects
repc creates the
rep_SimpleSwitch_source.hheader in the build directory that you specify. For more information, see Source .
repc creates three helper classes for use with QtRO. For this example, we use the basic:
SimpleSwitchSimpleSource. It’s an abstract class, defined in
rep_SimpleSwitch_source.h. We derive from it to define our SimpleSwitch implementation class as shown below:
simpleswitch.h#ifndef SIMPLESWITCH_H #define SIMPLESWITCH_H from rep_simpleswitch_source import * class SimpleSwitch(SimpleSwitchSimpleSource): Q_OBJECT # public SimpleSwitch(QObject parent = None) ~SimpleSwitch() virtual void server_slot(bool clientState) public Q_SLOTS: def timeout_slot(): # private stateChangeTimer = QTimer() #endif
QTimerthat is used to toggle the state of our SimpleSwitch.
timeout_slot()is connected to
stateChangeTimer's timeout() signal.
server_slot()– which is called automatically on the source whenever any replica calls their version of the slot – outputs the received value.
currStateChanged(bool), defined in the repc -generated
rep_SimpleSwitch_source.h, is emitted whenever
currStatetoggles. In this example, we ignore the signal on the source side, and handle it later on the replica side.
The definition of our
SwitchStateclass is shown below:
simpleswitch.cppfrom simpleswitch import * # constructor def __init__(self, SimpleSwitchSimpleSource(parent): stateChangeTimer = QTimer(self) # Initialize timer stateChangeTimer.timeout.connect(self.timeout_slot); // connect timeout() signal from stateChangeTimer to timeout_slot() of simpleSwitch stateChangeTimer.start(2000) # Start timer and set timout to 2 seconds print("Source Node Started") #destructor SimpleSwitch.~SimpleSwitch() stateChangeTimer.stop() def server_slot(self, clientState): print("Replica state is ", clientState) # print switch state echoed back by client def timeout_slot(self): # 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 print("Source State is ", currState())
Create a registry
Because this example uses a direct connection between nodes, we can omit this step.
Create a host node
The host node is created as shown below:srcNode = QRemoteObjectHost(QUrl("local:switch"))
Host source object and remoting
The following statements instantiate the Source object and pass it on to the host to enable “remoting”, which is the process of making an object visible to the QtRO network:SimpleSwitch srcSwitch # create simple switch srcNode.enableRemoting(srcSwitch) # enable remoting
The contents of
main.cppfile that implements the steps described above are as follows:
main.cppfrom PySide6.QtCore import QCoreApplication from simpleswitch import * if __name__ == "__main__": a = QCoreApplication(argc, argv) SimpleSwitch srcSwitch # create simple switch QRemoteObjectHost srcNode(QUrl("local:switch")) # create host node without Registry srcNode.enableRemoting(srcSwitch) # enable remoting/sharing return a.exec()
Compile and run this source-side project. The output, without any replicas created, should look as shown below with the switch state toggling between
falseevery two seconds.
The subsequent steps are for creating the replica side of the network, which in this example gets the state of switch from the Source and echoes it back.
Use repc to add a replica to your project
We use the same API definition file as we did on the source side,
SimpleSwitch.rep, to create a Replica header file using the repc . If you’re using
cmake, include the following line in your client side
cmakefile, specifying a
.repfile input:qt6_add_repc_replicas(directconnectclient simpleswitch.rep )
If you’re using
qmake, add the following line to your client side
.profile:REPC_REPLICA = simpleswitch.rep
Create a node to connect with the source’s host node
The following code instantiates the second node on the network and connects it with the source host node:QRemoteObjectNode repNode # create remote object node repNode.connectToNode(QUrl("local:switch")) # connect with remote host node
Call the node’s
acquire()to create a pointer to a replica
First, we instantiate a replica:ptr = QSharedPointer() ptr.reset(repNode.acquire<SimpleSwitchReplica>()) # acquire replica of source from host node
acquire()returns a pointer to the replica, but doesn’t manage its lifetime. This example shows the recommended process of wrapping the returned pointer in a
QScopedPointerto ensure that the pointer is always deleted properly.
main.cppimplements the steps described above and instantiates our object:
main.cppfrom PySide6.QtCore import QCoreApplication from client import * if __name__ == "__main__": a = QCoreApplication(argc, argv) QSharedPointer<SimpleSwitchReplica> ptr # shared pointer to hold source replica QRemoteObjectNode repNode # create remote object node repNode.connectToNode(QUrl("local:switch")) # 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()
The complete declaration and definition for the
Clientclass is as follows:
client.h#ifndef _CLIENT_H #define _CLIENT_H from PySide6.QtCore import QObject from rep_simpleswitch_replica import * class Client(QObject): Q_OBJECT # public Client(QSharedPointer<SimpleSwitchReplica> ptr) ~Client() def initConnections(): Q_SIGNALS: def echoSwitchState(server_slot(..): public Q_SLOTS: def recSwitchState_slot(): # private bool clientSwitchState # holds received server switch state QSharedPointer<SimpleSwitchReplica> reptr# holds reference to replica #endif
client.cppfrom client import * # constructor def __init__(self, ptr): QObject(None),reptr(ptr) initConnections() #We can connect to SimpleSwitchReplica Signals/Slots #directly because our Replica was generated by repc. #destructor Client.~Client() def initConnections(self): # initialize connections between signals and slots # connect source replica signal currStateChanged() with client's recSwitchState() slot to receive source's current state reptr.currStateChanged.connect(self.recSwitchState_slot) # connect client's echoSwitchState(..) signal with replica's server_slot(..) to echo back received state self.echoSwitchState.connect(reptr.server_slot) def recSwitchState_slot(self, value): print("Received source state ", value, reptr.data().currState()) clientSwitchState = reptr.data().currState() Q_EMIT echoSwitchState(clientSwitchState) # Emit signal to echo received state back to server
Compiling and running this example together with the source-side example generates the following output: