[Qt-interest] Unable to get sensible coordinate mappings
David Boddie
david.boddie at nokia.com
Mon May 18 19:04:00 CEST 2009
Andrew Hodgkinson wrote:
> Meanwhile, David Boddie wrote:
>
>> Out of interest, why don't you call showFullScreen() on the view?
>
> It's just the usual problem of 'discovery' when it comes to APIs :-)
>
> I'm new to Qt - only spent about 3 days programming to its API so far -
> and I didn't know the call existed. None of the "examples/graphicsview"
> Qt examples use it and the method is not described in:
>
> http://doc.trolltech.com/4.5/qgraphicsview.html
>
> Of course, it turns out it's inherited from QWidget. For me personally
> that wasn't an obvious place to look, because I'm still not used to
> thinking in the Qt way of "Widget" = "Window".
Yes, the documentation doesn't show all the inherited functions, and it's
tricky to know which of them specifically to mention in each subclass.
>> It sounds like you expect it to scale, but does it actually scale?
>
> Yes. The QGraphicsItem's paint() method calls "painter->setWindow" to
> specify its coordinate range and "painter->setViewport" (specifying scene
> coordinates) to map this range of item coordinates onto the scene. This
> works fine.
Right.
>> I'm not convinced that setting the sceneRect property does what you
>> expect, and some simple checks also led me to the conclusion that it
>> didn't do what I expected, either. :-/
>
> I wasn't being too clear, sorry.
No problem.
> The size of the rectangle returned by scene()->sceneRect(), in terms of
> its x(), y(), width() and height() methods' return values, matches my
> expectations - the pixel size of the virtual framebuffer is returned,
> which given the full-screen nature of the scene, is the "right" answer.
> I'm asking for the size via the scene rectangle object, so I expect it to
> given an answer in its own coordinate space.
>
> The painter routines are working; I paint over a coordinate range of
> (0,0) to (1279,719) in item coordinates and the viewport settings mean
> that the results of this are scaled as expected and painted onto the
> scene in the 'right' places by Qt without any extra effort by me.
OK.
> Trouble starts in the QGraphicsItem's "boundingRect" implementation.
> Documentation says that the object should return a value in item
> coordinates. Doing this leads to unexpected behaviour - only part of the
> item gets drawn onto the scene. Upon investigation it became apparent
> that the value seems to be (but this may be just an illusion /
> side-effect) interpreted as scene coordinates, not item coordinates. If I
> return simply the value of "scene()->sceneRect()" - i.e. make my
> QGraphicsItem claim that its 'drawn-on area' spans the whole of the
> scene, specified in scene coordinates - then I see the banner redrawn
> correctly regardless of scene resolution.
I suspect that the painting issues are caused by something other than
the coordinate mapping issues, though it's understandable that you
chose to investigate those first.
[...]
> Since the ability to specify window and viewport is done through the
> *painter* and NOT the QGraphicsItem then Qt can't actually do the mapping
> it claims. The ability to specify window and viewport through the painter
> and not the item seems at odds with the API from Qt 4.5 which says it
> provides mappings between item and scene coordinates. No wonder the
> return value of 'boundingRect' appears to be interpreted as if it were in
> scene (or parent) coordinates. It couldn't be treated any other way.
I suspect that this may be a side effect of your item's paint()
implementation. You just happened to choose to use setWindow() and
setViewport(), which cause problems with the painter's state. Indeed,
I have a nasty feeling that even calling save() and restore() before
and after painting isn't going to help if you use these functions. :-/
What you could do is to translate and scale the QPainter to describe the
mapping from your bannerArea rectangle to the rectangle inside it, and
simply return bannerArea from your boundingRect() implementation.
So, your item's paint() implementation would look something like this:
QRect bannerArea = QRect( 0, 0, 1280, 720 / 3 );
QRectF safeSceneRect = scene()->sceneRect();
qreal sceneSafeW = safeSceneRect.width() / 10;
qreal sceneSafeH = safeSceneRect.height() / 10;
// Using your code for this...
safeSceneRect.adjust(sceneSafeW, sceneSafeH, -sceneSafeW, -sceneSafeH);
safeSceneRect.setHeight((safeSceneRect.width() * bannerArea.height())
/ bannerArea.width());
painter.save();
painter.translate(sceneSafeW, sceneSafeH);
painter.scale(safeSceneRect.width()/bannerArea.width(),
safeSceneRect.height()/bannerArea.height());
// Do your painting here...
painter.restore();
Your boundingRect() implementation would be as you described:
QRectF SomeClassName::boundingRect() const
{
return QRectF(bannerArea);
}
>> If you're happy with the idea of scaling up from a scene containing
>> items placed within a 1280x720 rectangle then one thing you might want
>> to try is to set a transform on the view, mapping scene coordinates to
>> the screen geometry.
>
> Painting/scaling etc. is working nicely and matches my expectations
> based on the documentation. However, to get it to work perfectly the
> return value I must provide from the QGraphicsItem's "boundingRect"
> method is strange and all of the item-to-scene coordinate mapping methods
> return strange values. And in fact, I don't see how they could ever work.
> This is the part I don't understand.
I think the hard part comes from trying to take constraints on the output
and work backwards to figure out what to do with the item.
David
--
David Boddie
Senior Technical Writer
Nokia, Qt Software
More information about the Qt-interest-old
mailing list