Results 1 to 10 of 10

Thread: More on selective QGraphicsItem visibility

  1. #1
    Join Date
    Jan 2008
    Location
    Alameda, CA, USA
    Posts
    5,230
    Thanks
    302
    Thanked 864 Times in 851 Posts
    Qt products
    Qt5
    Platforms
    Windows

    Default More on selective QGraphicsItem visibility

    OK, in follow-up to my previous post, I have refactored my data plotting widget so that it uses a QGraphicsView instance only for the part of the plot that displays the data itself. The axes, titles, footers, etc. are displayed using QwtScaleWidget, QLabel, etc.

    One of the characteristics of this plot is that labels for the data points are drawn so that they don't collide or overlap, and that the size of the label does not scale (remains a fixed size) when the plot is zoomed in or out. This is accomplished with the ItemIgnoresTransformations flag.

    I have also implemented view-based collision detection: I create the candidate set of labels based on the zoom region in the view, then map the label positions and sizes from scene to view. I then go through this list and check for collisions; for any colliding pair of labels, the one with the lower z-value is made invisible. All of this works fine.

    The way I am trying to realize this on screen is to overlay two QGraphicsView windows. One window contains the data and its plot, the other contains only the labels. There are two QGraphicsScene instances, one for the data and plot, the other for the labels. The data scene can be shared among multiple plots, which allows me to display one in 1:1 format, the other zoomed in or out, etc. without having to duplicate the underlying data or scene objects. The label scene is dedicated to the QGraphicsView that displays the labels. In this way, two views of the same scene could have a different set of non-colliding labels, as a sort of "level of detail" effect.

    The problem I am having is that I cannot seem to make both graphics views simultaneously visible. I have tried various versions of this code in my plot widget constructor:

    Qt Code:
    1. mpCanvas = new QGraphicsView( this );
    2. mpCanvas->setViewportUpdateMode( QGraphicsView::FullViewportUpdate );
    3. mpCanvas->setEnabled( true );
    4. mpCanvas->setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOff );
    5. mpCanvas->setVerticalScrollBarPolicy( Qt::ScrollBarAlwaysOff );
    6. mpCanvas->setWindowOpacity( 0.0 );
    7. mpCanvas->setBackgroundBrush( Qt::NoBrush );
    8.  
    9. mpLabelCanvas = new QGraphicsView( &mLabelScene, this );
    10. mpLabelCanvas->setViewportUpdateMode( QGraphicsView::FullViewportUpdate );
    11. mpLabelCanvas->setEnabled( false );
    12. mpLabelCanvas->setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOff );
    13. mpLabelCanvas->setVerticalScrollBarPolicy( Qt::ScrollBarAlwaysOff );
    14.  
    15. mpLabelCanvas->stackUnder( mpCanvas );
    To copy to clipboard, switch view to plain text mode 

    where "mpCanvas" is the QGraphicsView that uses the shared QGraphicsScene containing the data, and "mpLabelCanvas" is the QGraphicsView with the dedicated scene holding the labels. (Scenes are assigned later in the constructor, and labels are calculated on-the-fly during resize and zoom operations).

    In the version posted above, the "mpCanvas" is visible, the "mpLabelCanvas" is not. (I see the data but no labels). If I stack them the other way, the opposite occurs, so I know that I am positioning, sizing, and setting transforms for the two views correctly.

    What I want to happen is that the upper (data) view is transparent so that the lower (label) view shows through it. This is my last hurdle in getting this widget to a state where I can actually write the app that uses it.

    Is there some combination of window flags, opacity, background brush, etc. that will create this effect?
    Last edited by d_stranz; 12th February 2013 at 21:19.

  2. #2
    Join Date
    Feb 2008
    Posts
    491
    Thanks
    12
    Thanked 142 Times in 135 Posts
    Qt products
    Qt4 Qt5
    Platforms
    Unix/X11

    Default Re: More on selective QGraphicsItem visibility

    Will setStyleSheet work:
    Qt Code:
    1. mpCanvas->setStyleSheet("background : transparent");
    To copy to clipboard, switch view to plain text mode 

  3. The following user says thank you to norobro for this useful post:

    d_stranz (13th February 2013)

  4. #3
    Join Date
    Mar 2011
    Location
    Hyderabad, India
    Posts
    1,882
    Thanks
    3
    Thanked 452 Times in 435 Posts
    Qt products
    Qt4 Qt5
    Platforms
    MacOS X Unix/X11 Windows
    Wiki edits
    15

    Default Re: More on selective QGraphicsItem visibility

    mpCanvas->setWindowOpacity( 0.0 );
    This will not help you to get to what you wanted in the first place. Making a widget transparent will make all the contents loose their opacity too, i.e. the items on the QGrpahicsView will blend into the back ground (below) QGraphicsView, but where as you need the top QGraphicsView items to be overwritten (visible solid) on the bottom QGraphcisView.

    So the only way I see out is to se the view's backgroud to transparent

    Just a side note, you could also use QStackedLayout in StackAll mode, and set transparent backgroud. Here you can use the features which layouts give, if wanted to.
    When you know how to do it then you may do it wrong.
    When you don't know how to do it then it is not that you may do it wrong but you may not do it right.

  5. The following user says thank you to Santosh Reddy for this useful post:

    d_stranz (13th February 2013)

  6. #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: More on selective QGraphicsItem visibility

    Instead of composing two views together, draw content of one scene in the other view's drawForeground() implementation. Or just have one scene only and draw the labels in the drawForeground() call without storing them in a separate scene.
    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.


  7. The following user says thank you to wysota for this useful post:

    d_stranz (13th February 2013)

  8. #5
    Join Date
    Jan 2008
    Location
    Alameda, CA, USA
    Posts
    5,230
    Thanks
    302
    Thanked 864 Times in 851 Posts
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: More on selective QGraphicsItem visibility

    Instead of composing two views together, draw content of one scene in the other view's drawForeground() implementation. Or just have one scene only and draw the labels in the drawForeground() call without storing them in a separate scene.
    Oh, I like this idea. Much simpler than my semi-solution. I had considered doing something similar using the paint event in the main widget, but that would have been complicated. Very nice that the foreground drawing is in scene coordinates so I don't have to worry about transformations at that point.

    Thanks to the others for their suggestions as well.

  9. #6
    Join Date
    Jan 2008
    Location
    Alameda, CA, USA
    Posts
    5,230
    Thanks
    302
    Thanked 864 Times in 851 Posts
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: More on selective QGraphicsItem visibility

    OK, this turned out to be trickier than anticipated, but it is working.

    Very nice that the foreground drawing is in scene coordinates so I don't have to worry about transformations at that point.
    This bit turned out to be not as true as I would have liked. I could not get the QGraphicsSimpleTextItem instances representing the labels to draw by simply using the QGraphicsSimpleTextItem:: paint() method. For whatever reason, nothing appeared. I verified that other types of QGraphicsItem could be rendered this way (like a QGraphicsRectItem with position and size in scene coordinates). So what I ended up implementing was something like the following:

    Qt Code:
    1. // MyGraphicsView inherits from QGraphicsView
    2. // mForegroundItems is a vector of QGraphicsItem pointers passed into the view; in the case of text items (labels)
    3. // these have been filtered to eliminate items that collide *in this view*. The text items have ItemIgnoresTransformations set.
    4.  
    5. void MyGraphicsView::drawForeground( QPainter * pPainter, const QRectF & rect )
    6. {
    7. QGraphicsView::drawForeground( pPainter, rect );
    8.  
    9.  
    10. std::vector< QGraphicsItem * >::iterator it = mForegroundItems.begin();
    11. std::vector< QGraphicsItem * >::iterator eIt = mForegroundItems.end();
    12. while ( it != eIt )
    13. {
    14. QGraphicsItem * pItem = *it++;
    15. if ( pItem )
    16. {
    17. if ( pItem->type() == QGraphicsSimpleTextItem::Type )
    18. {
    19. QGraphicsSimpleTextItem * pText = qgraphicsitem_cast< QGraphicsSimpleTextItem *>( pItem );
    20. QPointF pos = mapFromScene( pText->pos() );
    21.  
    22. pPainter->save();
    23. pPainter->resetTransform();
    24. pPainter->setFont( pText->font() );
    25. if ( pText->pen() != Qt::NoPen )
    26. pPainter->setPen( pText->pen() );
    27. pPainter->setBrush( pText->brush() );
    28. pPainter->drawText( pos, pText->text() );
    29. pPainter->restore();
    30. }
    31. else
    32. pItem->paint( pPainter, &option, this );
    33. }
    34. }
    35. }
    To copy to clipboard, switch view to plain text mode 

    Basically, the text had to be painted as ordinary text at the correct pixel position as mapped from the scene. Prior to painting, it was necessary to reset the painter's transform (since it comes into this method with the scene transformation already applied), then restore it before exiting.

    Note that this solution is specific to my needs: labels are a fixed pixel size and do not scale with the scene scaling, and labels are always drawn in horizontal orientation.

    If there's a better way to do this, I'd be interested to know. In particular, I don't understand why I can't draw text items directly using the paint() call. Possibly it is because the items are not children of the scene (i.e. QGraphicsScene::addItem() is not called, and the items have no QGraphicsItem parent), but on the other hand, the QGraphicsRect item I drew in testing this method wasn't either, but did not have the ItemIgnoresTranformations flag set.

    Whatever, this suggestion of using drawForeground() has turned out to be very useful. I have also implemented an override of drawBackground() for this view class, which will allow me to display Qwt "spectrogram" style images as a background pixmap, overlaid with QGraphicsItem things in the scene to allow for marking and selecting "features" in the image.

  10. #7
    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: More on selective QGraphicsItem visibility

    I don't understand why you are using items for your foreground. It does not make much sense to me. If you want to use items then have two scenes and render one in the other's drawForeground().
    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.


  11. #8
    Join Date
    Jan 2008
    Location
    Alameda, CA, USA
    Posts
    5,230
    Thanks
    302
    Thanked 864 Times in 851 Posts
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: More on selective QGraphicsItem visibility

    I don't understand why you are using items for your foreground.
    For convenience mostly, and because I had already implemented an "aligned text item" that allows me to specify the text alignment relative to the pos() (using Qt::Alignment flags). There's a signal / slot pair that lets the view query the curves drawn in the plot for their set of proposed text labels. In the previous implementation, these labels were placed in the scene; in the current implementation, they are drawn in the foreground instead.

    If you want to use items then have two scenes and render one in the other's drawForeground().
    I don't understand this. Of the set of candidate labels returned by the curve, the labels that are actually displayed are view specific and depend on the screen size and section of the scene that is zoomed into in that view. The view takes the combined list of labels returned by each curve and ranks them by z-value, then eliminates any labels with lower z-value that collide with one of higher z. This list is then used in my view's drawForeground() as shown above.

    Are you suggesting that these items should be added to a separate scene (maintained by each view), and that the "master" scene should render the appropriate additional scene in its drawForeground() method? How do I identify which view is the target in this method?

  12. #9
    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: More on selective QGraphicsItem visibility

    Quote Originally Posted by d_stranz View Post
    Are you suggesting that these items should be added to a separate scene (maintained by each view),
    Yes, that's exactly what I mean.

    and that the "master" scene should render the appropriate additional scene in its drawForeground() method? How do I identify which view is the target in this method?
    No no. The view does that in QGraphicsView::drawForeground().

    Hmm... maybe I should write a paper on this, I have played with such solution for some time and it works nice and people often ask for things like this.
    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.


  13. #10
    Join Date
    Jan 2008
    Location
    Alameda, CA, USA
    Posts
    5,230
    Thanks
    302
    Thanked 864 Times in 851 Posts
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: More on selective QGraphicsItem visibility

    No no. The view does that in QGraphicsView::drawForeground().
    Ah, I see. I had tried using two scenes at one time, but I was also trying to overlay two QGraphicsView instances. I could not get that to work.

    OK, I will give this a try. I admit that I felt that what I now am doing is somewhat kludgy. I'll have to pay close attention to what happens during zooming so I can keep the two scenes synchronized.

    A paper would be a welcome addition.

Similar Threads

  1. Replies: 2
    Last Post: 1st February 2013, 20:59
  2. Selective signaling
    By csaken in forum Qt Programming
    Replies: 15
    Last Post: 30th April 2010, 09:13
  3. Visibility with styleSheets
    By jano_alex_es in forum Newbie
    Replies: 2
    Last Post: 21st January 2010, 11:14
  4. QTabWidget tab visibility
    By dcss-design in forum Qt Programming
    Replies: 2
    Last Post: 30th January 2007, 23:24
  5. Selective highlighting of Items
    By Kapil in forum Qt Programming
    Replies: 3
    Last Post: 26th May 2006, 12:20

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.