Results 1 to 6 of 6

Thread: Design Issue with Qt

  1. #1
    Join Date
    Jun 2012
    Posts
    58
    Thanks
    13
    Qt products
    Qt4

    Default Design Issue with Qt

    using Qt 5.0.0

    The following is roughly an Observer pattern (the code is stripped to bare minimum to explain only the problem - pls don't judge the use of the design pattern by the 'looks' of the code here):

    Qt Code:
    1. class A : public QObject
    2. {
    3. Q_OBJECT
    4. public:
    5. void registerListner(Observer *pObs);
    6. static A* getInstance();
    7. signals:
    8. void sig();
    9. };
    10.  
    11. void A::registerListner(Observer *pObs)
    12. {
    13. connect(this, SIGNAL(sig()), pObs, SLOT(slo));
    14. }
    15.  
    16. ////////////////////////////////////////////////////////////////
    17.  
    18. class Observer : public QObject
    19. {
    20. Q_OBJECT
    21. public slots:
    22. virtual void slo() = 0;
    23. };
    24.  
    25. class ConcreteObserver : public Observer , public QWidget
    26. {
    27. Q_OBJECT
    28. public: //re-mentioning "slots" is not necessary i suppose
    29. virtual void slo();
    30. };
    31.  
    32. ConcreteObserver *pCObs = new ConcreteObserver;
    33. A::getInstance()->registerListner(pCObs);
    34.  
    35. /////////////////////////////////////////////////////////////
    To copy to clipboard, switch view to plain text mode 
    problem (apart from dreaded-diamond): Can't inherit multiple times from QObject - moc does not allow it. One possible solution is derive Observer from QWidget and then ConcreteObserver from Observer alone. However this is putting a constraint on ConcreteObserver. Maybe ConcreteObserver_2 needs to derive from QDialog instead etc.

    How do i solve this design problem? Is there anything specific to Qt 5.0.0 Signal-Slot (in addition to earlier versions) that can solve this, or what would you suggest?

  2. #2
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: Design Issue with Qt

    Observer doesn't have to inherit QObject. You can remove the whole mechanism in favor of directly connecting signals and slots instead of calling registerListener().
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


  3. #3
    Join Date
    Jun 2012
    Posts
    58
    Thanks
    13
    Qt products
    Qt4

    Default Re: Design Issue with Qt

    Could you please elaborate? Note that classes A and Observer will be part of the library framework and ConcreteObserver and the other code would be the client GUI/non-GUI code. Observer may have hundreds of pure virtual slots and registerListner may connect all of them to other hundreds of signals. The idea is to force the users to define all of them (slots) so that when they register to class A, no connection would be wrong (which would otherwise be apparent only during the runtime as connections are not checked during compile time unless we use function pointers/functors of Qt 5 - never used the latest connection mechanism so not very sure on this one).

  4. #4
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: Design Issue with Qt

    You need to understand why and when we use signals and slots (this is the third time I'm writing this in the last few weeks...). The mechanism allows to implement the so called "loosely coupled objects" paradigm (http://en.wikipedia.org/wiki/Loose_coupling). In short this means we can combine objects to function together while knowing nothing about each other. This is usually done when we have three contexts -- A, B and C. A and B know nothing of each other and C knows both A and B. This lets us to connect A and B in context C. In your situation you have just two contexts -- observer and observee (you are connecting a signal from "this") and they have to know something about each other (at least the presence of specified slots in the observer). So in the end the observee has access to a list of observers (as each has to be registered with it) and knows its interface directly. Thus instead of using signals and slots (where a signal doesn't know if anything is connected to it and what is the name of the slot(s)) you can just call specific methods directly.

    Qt Code:
    1. void Observee::registerObserver(Observer *o) {
    2. m_observers << o;
    3. }
    4.  
    5. void Observee::notifySlo() {
    6. foreach(Observer *o, m_observers) o->slo();
    7. }
    To copy to clipboard, switch view to plain text mode 

    Thus no need for any QObject legacy.

    On the other hand, signals and slots implements the Observer/Listener pattern itself. Thus you don't need to have any "Observer" interface nor any "Observee" interface because QObject already handles that. You can just connect signals and slots directly letting the observer decide which signals to connect to and which to ignore. Thanks to that he doesn't have to implement all those "hundreds of" slots if he's just interested in one signal. If you wish to have some control over it, you can wrap the connect statement in a function like you did but allowing the caller to specify the slot:

    Qt Code:
    1. void Observee::registerObserver(QObject *rcvr, const char *slt) {
    2. if(!connect(this, SIGNAL(sig()), rcvr, slt)){
    3. qWarning() << "Connection failed";
    4. }
    5. }
    6.  
    7. // ...
    8.  
    9. x->registerObserver(this, SLOT(mySlot()));
    To copy to clipboard, switch view to plain text mode 

    Of course you can remove the whole registerObserver() call whatsoever and just let the caller specify both the signal and the slot.
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


  5. #5
    Join Date
    Jun 2012
    Posts
    58
    Thanks
    13
    Qt products
    Qt4

    Default Re: Design Issue with Qt

    Your first code looks more like a Qt's direct connection so i guess we will have to additionally take care when object's have different thread affinities. The second one is i suppose what i'm partially looking for. I wanted to force, by design, the users registering to implement all the slots that would be connected in registerListener. In what you showed (using QObject* instead of Observer*) i think i might achieve that at runtime using assert(connect(signal <--> slot)) and if the Observer (in this case a QObject*) does not have the required slots, one of such asserts would fail. That's almost what i want but would have been nice if i could do it statically. But i suppose there isn't a straightforward way for this or you would have told me.

    I even tried this:
    Qt Code:
    1. template<typename Base>
    2. class Observer : public Base
    3. {
    4. Q_OBJECT
    5. public slots:
    6. virtual void slo1() = 0;
    7. virtual void slo2() = 0;
    8. // ....etc
    9. }; //checking if Base derives from QObject is easy - static_cast checking should do the trick
    10.  
    11. Then the user could have the flexibility of doing:
    12. class ConcreteObserverUser : public Observer<QWidget>
    13. {
    14. Q_OBJECT
    15. public slots:
    16. virtual void slo1();
    17. virtual void slo2();
    18. // ...etc
    19. };
    To copy to clipboard, switch view to plain text mode 

    But again i got a moc error that templates cannot be used with Q_OBJECT . So i guess that static checking (leading to a compile time error) will not be possible elegantly

  6. #6
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: Design Issue with Qt

    Why do you want to force every slot to be implemented? It seems to me like trying to be smarter than the person that is going to be using the class I design. You offer some functionality to someone and it is his choice to use as much from this functionality as she/he wants. Trying to force her/him to use all observer callbacks doesn't feel like non-intrusive "observer" pattern.

    If you really really really want to check if a class implements all the slots then you can do that using QMetaObject:

    Qt Code:
    1. void checkAllSlotsExist(QObject *obj) {
    2. const QMetaObject *mo = obj->metaObject();
    3. assert(mo->indexOfMethod("slo1()") >=0);
    4. assert(mo->indexOfMethod("slo2()") >=0);
    5. assert(mo->indexOfMethod("slo3()") >=0);
    6. assert(mo->indexOfMethod("slo4()") >=0);
    7. // ...
    8. }
    To copy to clipboard, switch view to plain text mode 
    You can substitute asserts with returning false to have a soft-fail version. But I still think such checks are just plain wrong. If I were to use your class and saw that I had to implement 300 empty functions just to use one, I would rather connect to the signal directly instead of using your observer pattern. Which would make your Observer class totally redundant and/or obsolete.
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


Similar Threads

  1. Replies: 1
    Last Post: 22nd October 2012, 10:54
  2. Typical Design Issue
    By sajis997 in forum Qt Programming
    Replies: 4
    Last Post: 24th January 2012, 16:14
  3. Replies: 3
    Last Post: 5th October 2008, 23:41
  4. Dialog and code design issue
    By Gopala Krishna in forum Qt Programming
    Replies: 1
    Last Post: 24th September 2006, 17:54
  5. A Design Issue...
    By nupul in forum Qt Programming
    Replies: 6
    Last Post: 4th May 2006, 17:41

Tags for this Thread

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Digia, Qt and their respective logos are trademarks of Digia Plc in Finland and/or other countries worldwide.