[Solved] How can I know which slot cares about the signal I'm about to send?
-
I have an application which uses a REST client to retrieve data from a web service. The REST client encapsulates the protocols used to communicate with the service, so an object that wants data from the service will connect a SLOT to the appropriate REST client's SIGNAL for that data, then it calls the method to submit the request for the data (eg. requestEmployeeList(queryParams)). The REST client sends the request to the service, and parses the reply later when it arrives, marshals the data into an appropriate data object (eg. QList<Employee>), and emits it.
The application has multiple QTableViews attached to multiple models derived from QAbstractTableModel. These views and models need to communicate with the REST service by connecting slots to the REST client and calling its methods for requesting/posting data.
Since the network replies are signaled asynchronously, the REST client doesn't know which object requested it, so it currently emits the appropriate signal for whatever kind of reply it receives. I'd rather have a way to communicate specifically with the object that made the request, but apart from instantiating a REST client per model and view that needs one, I'm having trouble coming up with an elegant way to do this.
-
@whereness I don't understand why you want to "communicate specifically with the object that made the request". It seems the signal/slot system you have is fine. I don't get why you want to make things more complex.
But anyway if I understand what you want you should do something like:
Make your request methods public slots.
Create request/post signals in your tables
Connect the signals to the appropriate slots
When they want data emit those signals then catch them:RestClient::requestSlot(WhateverObject object){ Table table = qobject_cast<Table>(sender()); // Do whatever }
-
@raf924 said:
@whereness I don't understand why you want to "communicate specifically with the object that made the request". It seems the signal/slot system you have is fine. I don't get why you want to make things more complex.
Say I have 2 employee model instances, one will query for employees at location 1, the other will query for employees at location 2. Each one will connect a slot to the REST client's employeeListReady(QList<Employee> &) signal and make their respective requests (i.e. they're unique instances of the same model class). The REST client will do its own signal/slot connections and make each request, then later when the replies signal finished(), it will parse each reply and dutifully signal with the list. Both models' slots are called for each reply. How do the models know which signal was meant for it's particular request? I can't have signals for each type of query (eg. location 1, location 2) because the UI allows user-specified queries (eg. location 1, lastname Smith). I could return the QNetworkReply pointer for each request, then the REST client would have to pass that along in it's signal to the models, then the models would have to keep track of them and check its reply object list to decide whether the signal was for them or not. But that seems messy. I'm thinking each model should have it's own REST client instance to avoid all of that, but that seems wasteful, as there will be many models and UI objects that will need to make REST requests. Seems like I'm missing something...
-
@whereness Don't use signals on the restclient side, do as i proposed:
@raf924 said:
Make your request methods public slots.
Create request/post signals in your tables
Connect the signals to the appropriate slots
When they want data emit those signals then catch them:RestClient::requestSlot(WhateverObject object){ Table table = qobject_cast<Table>(sender()); // Do whatever }
-
@raf924 said:
@whereness Don't use signals on the restclient side, do as i proposed:
@raf924 said:
Make your request methods public slots.
Create request/post signals in your tables
Connect the signals to the appropriate slots
When they want data emit those signals then catch them:RestClient::requestSlot(WhateverObject object){ Table table = qobject_cast<Table>(sender()); // Do whatever }
If I follow, you're proposing the table emit a signal when it wants data. The the restclient still needs to make the asynchronous request for data from the server, so unless I cache the table pointer on the restclient and associate it with the QNetworkReply pointer somehow, I still have the same problem. Maybe that goes with what you're suggesting? Unfortunately, there will be more than just that object type wanting to request data (eg. QTableModel derivatives), so the casting may get ugly. Maybe I'm still missing something. Thanks for your help BTW.
-
Hi,
One way to implement that is for the client to return an object doing the parsing of the QNetworkReply and emitting a signal when all is ready. So you can re-use your client singleton in multiple objects without the need of much intelligence in it. You can take a look at the qtenginio module for inspiration.
Hope it helps
-
@whereness When i say "tables" i mean the type that will emit the signal you can test which class to cast like this:
if (qobject_cast<TableModel>(sender()) != NULL) { /* yourobjectpointer is an instance of YourQClass which should be a QObject subclass */ }
or like this
if(sender()->metaObject()->className()=="TableModel")
Or try to have only one requester type which you subclass but that will require you to alter the architecture of your program i guess.
But yes the need to cache the table pointer goes away with my suggestion (that was the whole point of it) because it is retrieved with the sender method -
@raf924 said:
@whereness When i say "tables" i mean the type that will emit the signal you can test which class to cast like this:
if (qobject_cast<TableModel>(sender()) != NULL) { /* yourobjectpointer is an instance of YourQClass which should be a QObject subclass */ }
or like this
if(sender()->metaObject()->className()=="TableModel")
Or try to have only one requester type which you subclass but that will require you to alter the architecture of your program i guess.
But yes the need to cache the table pointer goes away with my suggestion (that was the whole point of it) because it is retrieved with the sender methodIt would still have to be cached in the restclient because the response from the webserver arrives asynchronously of the request for data.
-
@whereness Oh yeah my bad I was so focused on the part where you communicate with the objects i forgot about the actual web query. You can use this : http://doc.qt.io/qt-5/qnetworkrequest.html#setOriginatingObject
then get it back with this http://doc.qt.io/qt-5/qnetworkreply.html#request. -
@raf924 said:
@whereness Oh yeah my bad I was so focused on the part where you communicate with the objects i forgot about the actual web query. You can use this : http://doc.qt.io/qt-5/qnetworkrequest.html#setOriginatingObject
then get it back with this http://doc.qt.io/qt-5/qnetworkreply.html#request.Yes! Thanks!
-
@whereness You're welcome don't forget to add [SOLVED] to your topic title
-
@SGaist said:
Hi,
One way to implement that is for the client to return an object doing the parsing of the QNetworkReply and emitting a signal when all is ready. So you can re-use your client singleton in multiple objects without the need of much intelligence in it. You can take a look at the qtenginio module for inspiration.
Hope it helps
I ended up going this route, as how things were, this had less impact on existing code and seemed more straightforward API-wise. Thanks.