Results 1 to 6 of 6

Thread: Dreaded Diamond Issue with QGraphicsWidget and QObject

  1. #1
    Join Date
    Mar 2009
    Posts
    14
    Thanks
    3
    Thanked 1 Time in 1 Post
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Question Dreaded Diamond Issue with QGraphicsWidget and QObject

    In short, I'm looking for a way to get around a multiple inheritance problem and would like to know if there's a Qt-esque solution for what I'm trying to achieve. Read on for more info.

    I've developed an abstract base class, Foo, as a subclass of QGraphicsProxyWidget for a number of different QWidget-based graphics items, WarmFoo and HotFoo. These items share a lot of the same code in the Foo, most importantly various features of QObject, including Q_PROPERTY definitions, and signals / slots. Everything has worked fine, but I want to expand the capabilities a bit more.

    I want to derive a new subclass of QGraphicsWidget, ColdFoo, to take advantage of some of the performance increases you get by avoiding QGraphicsProxyWidget. But I'd also like to derive the same class from Foo to use the methods and attributes I've built up for the widget-based items. The class inheritances that I've come up with so far all have a dreaded diamond leading to a ambiguous base class error.

    Here is the current inheritance diagram along with some other structures I've considered to solve the problem.

    Qt Code:
    1. /*
    2.  * QGraphicsProxyWidget
    3.  * ^
    4.  * |
    5.  * Foo <------ HotFoo
    6.  * ^
    7.  * |
    8.  * WarmFoo
    9.  *
    10.  * This is how the inheritance works now.
    11.  */
    12.  
    13. /*
    14.  * QGraphicsWidget <--- QGraphicsProxyWidget
    15.  * ^ ^
    16.  * | |
    17.  * Foo <---------------- FooProxy <------ HotFoo
    18.  * ^ ^
    19.  * | |
    20.  * ColdFoo WarmFoo
    21.  *
    22.  * In this possiblity, Foo is re-subclassed to
    23.  * extend QGraphicsWidget and FooProxy maintains
    24.  * a specialization for already made widgets. The
    25.  * dreaded diamond extends down from QGraphicsWidget
    26.  * to FooProxy.
    27.  */
    28.  
    29. /*
    30.  * /----- QGraphicsWidget <-------- QGraphicsProxyWidget
    31.  * | ^ ^
    32.  * v | |
    33.  * QObject FooWidget <--- ColdFoo /--- FooProxy <--- HotFoo
    34.  * ^ | | ^
    35.  * | v | |
    36.  * \---------- Foo <-----------------/ WarmFoo
    37.  *
    38.  * In this possiblilty, Foo is completely detached
    39.  * from the graphics subsystem, yet still extends
    40.  * QObject because of the object subsystem features
    41.  * it uses. The dreaded diamond exists down from
    42.  * QObject to FooWidget and FooProxy.
    43.  */
    To copy to clipboard, switch view to plain text mode 

    Is there a way to handle or get around such a thing using the facilities available in Qt? Maybe use QGraphicsProxyWidget in such a way that it behaves like a QGraphicsWidget?

    Or perhaps what I really need to be do is pull the QObject-related info out of the new Foo class and move it to each of Foo's subclasses. I'd like to avoid maintaining the same code in multiple places as a top priority, for obvious reasons.

    Thoughts? Ideas? Thanks for the feedback!

    If nothing else, I hope you enjoyed my ASCII inheritance diagrams...

  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: Dreaded Diamond Issue with QGraphicsWidget and QObject

    Use the "bridge" design pattern or derive your Foo from QGraphicsWidget and for the items that require a proxy instantiate a proxy widget and make it a child of a blank Foo subclass that will forward all request to the embedded item. AFAIR that's a "proxy" design pattern.
    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
    Mar 2009
    Posts
    14
    Thanks
    3
    Thanked 1 Time in 1 Post
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Lightbulb Re: Dreaded Diamond Issue with QGraphicsWidget and QObject

    I've been weighing and testing some of the the trade-offs between bridges and proxies... it's looking like the proxy solution is more feasible for what I've got implemented already. I'll let you know how it turns out.

    Other thoughts are also appreciated!

  4. #4
    Join Date
    Mar 2009
    Posts
    14
    Thanks
    3
    Thanked 1 Time in 1 Post
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Arrow Re: Dreaded Diamond Issue with QGraphicsWidget and QObject

    I'm looking into a couple of ways to run proxy-esque patterns to achieve what I'm trying to do.

    In this first configuration based off of the first possibility in my first post, the inheritance between QGraphicsProxyWidget and FooProxy has been removed.

    Qt Code:
    1. /*
    2.  * QGraphicsWidget <--- QGraphicsProxyWidget
    3.  * ^
    4.  * |
    5.  * Foo <---------------- FooProxy <------ HotFoo
    6.  * ^ ^
    7.  * | |
    8.  * ColdFoo WarmFoo
    9.  */
    To copy to clipboard, switch view to plain text mode 

    FooProxy now contains an attribute of type QGraphicsProxyWidget pointer called _proxy. Methods are written to redirect calls to _proxy where necessary. As a simplified example, consider the following.

    Qt Code:
    1. class FooProxy : public Foo {
    2. QGraphicsProxyWidget * _proxy;
    3.  
    4. public:
    5. // this works fine for simple calls...
    6. void setWidget(QWidget * widget) {_proxy->setWidget(widget);}
    7.  
    8. protected:
    9. // ...but what happens now?
    10. virtual void contextMenuEvent(QGraphicsSceneContextMenuEvent * event) {
    11. // this method is protected in _proxy and cannot be called in this context
    12. _proxy->contextMenuEvent(event);
    13.  
    14. // maybe a potential solution is something like this
    15. QCoreApplication::sendEvent(_proxy, event);
    16. }
    17.  
    18. // ...but that technique wont help here
    19. virtual bool focusNextPrevChild(bool next) {
    20. // this method is also protected in _proxy
    21. return _proxy->focusNextPrevChild(next);
    22. }
    23. }
    To copy to clipboard, switch view to plain text mode 

    I can't continue on this structure until I find a way to get at the protected methods in _proxy, or find another way of calling these methods.

    For an alternative configuration based off of the second possibility from my earlier post, I could re-subclass Foo to extend QObject, and remove the graphics subsystem inheritance from FooWidget and FooProxy.

    Qt Code:
    1. /*
    2.  * /----- QGraphicsWidget <-------- QGraphicsProxyWidget
    3.  * |
    4.  * v
    5.  * QObject FooWidget <--- ColdFoo /--- FooProxy <--- HotFoo
    6.  * ^ | | ^
    7.  * | v | |
    8.  * \---------- Foo <-----------------/ WarmFoo
    9.  */
    To copy to clipboard, switch view to plain text mode 

    To guarantee that FooWidget and FooProxy always maintain a graphics system like appearance (in terms of available methods), each relevant method will need to be added as pure virtual in Foo. That's a lot of methods! I'm still working through this before I can show some code example.

    Thoughts?

  5. #5
    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: Dreaded Diamond Issue with QGraphicsWidget and QObject

    Call event() which is public - the event will get forwarded to the proper event handler by it. Or resend the event to the other object using regular means, the effect will be similar.

    Although I'd probably use the bridge pattern, for me it seems cleaner in this situation, at least on the first look.
    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.


  6. #6
    Join Date
    Mar 2009
    Posts
    14
    Thanks
    3
    Thanked 1 Time in 1 Post
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Thumbs up Re: Dreaded Diamond Issue with QGraphicsWidget and QObject

    After developing into it, yes the bridge pattern made more sense because less code would have to be maintained over few classes. And I ended up using an event filter for handling the events. When the graphic is added to the scene, I pass in Foo::_widget via an accessor rather than Foo itself as I had been doing.

    So here's the (bastardized) bridge configuration that I settled on, with a little code example for Foo, and everything seems to work well!

    Qt Code:
    1. /*
    2.  * /----- QGraphicsWidget <-------- QGraphicsProxyWidget
    3.  * | ^
    4.  * v |
    5.  * QObject ColdFoo
    6.  * ^ | |
    7.  * | v
    8.  * \---------- Foo <--- HotFoo - - - - - - - - /
    9.  * ^ |
    10.  * |
    11.  * WarmFoo - - - - - - - - - - - - - /
    12.  *
    13.  * The final configuration is based off the second
    14.  * possibility from my first post. FooWidget and
    15.  * FooProxy could be removed because of the bridge
    16.  * pattern. HotFoo and WarmFoo extend Foo with a
    17.  * QGraphicsProxyWidget passed into the constructor.
    18.  * ColdFoo does the same with other
    19.  * QGraphicsWidget-based subclasses.
    20.  */
    21.  
    22. class Foo : public QObject
    23. {
    24. Q_OBJECT
    25.  
    26. // All of the properties that I need for QGraphicsWidget-based classes are defined here
    27. Q_PROPERTY(QRectF geometry READ geometry WRITE setGeometry)
    28. ...
    29.  
    30. protected:
    31. // The widget to bridge to
    32. QGraphicsWidget * _widget;
    33.  
    34. public:
    35. // Instantiate our Foo and _widget with an event filter
    36. Foo(QGraphicsWidget * widget, QObject * parent = 0) : QObject(parent), _widget(widget) {
    37. _widget->installEventFilter(this);
    38. }
    39.  
    40. bool eventFilter(QObject * watched, QEvent * event) {
    41. // Redirects events to event filter methods defined below
    42. ...
    43. }
    44.  
    45. protected:
    46. // Filtered relevant events
    47. virtual bool mousePressEventFilter(QGraphicsSceneMouseEvent * event) {...}
    48. ...
    49.  
    50. private:
    51. // Accessors for properties declared above
    52. QRectF geometry() const {return _widget->geometry();}
    53. void setGeometry(const QRectF rect) {_widget->setGeometry(rect);}
    54. ...
    55.  
    56. }
    To copy to clipboard, switch view to plain text mode 
    Last edited by perden; 18th June 2010 at 19:56. Reason: minor fixed to code example

Similar Threads

  1. QTextEdit on a QGraphicsWidget
    By paolom in forum Qt Programming
    Replies: 2
    Last Post: 7th October 2009, 14:08
  2. Positioning QGraphicsWidget
    By jasper_ferrer in forum Qt Programming
    Replies: 3
    Last Post: 22nd September 2009, 14:34
  3. grabMouse() on QGraphicsWidget()
    By wagmare in forum Qt Programming
    Replies: 1
    Last Post: 7th August 2009, 07:27
  4. QGraphicsWidget - How does it work?
    By been_1990 in forum Qt Programming
    Replies: 2
    Last Post: 31st July 2009, 13:15
  5. QGraphicsWidget vs. QGraphicsRectItem
    By Bill in forum Newbie
    Replies: 3
    Last Post: 27th July 2009, 09:02

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.