I asume you used some form of the draw items section of the QGraphicsView paintEvent
No, as I said, I implemented QGraphicsView::drawForeground() in my derived class, and call QGraphicsScene::render() on the captive scene.
But if I do not need any of the benefits of the scene transform (all I need is position), is storing them in a dedicated scene the right place?
It makes life easier, because these are view-specific items and can't be part of the generic scene. If you never intend to share the same scene with multiple views, then you can simply put them in the main scene and scale them appropriately. But if you will be displaying the same scene in several places, with potentially different viewports and scales, then you need to use a different mechanism. I found this easier to implement. The guts of it are dead simple:
void CustomView
::drawForeground( QPainter * pPainter,
const QRectF & rect
) {
mForegroundScene.
render( pPainter, rect,
QRectF(), Qt
::IgnoreAspectRatio );
}
void CustomView
::onSceneRectChanged( const QRectF & rect
) {
setSceneRect( rect );
mForegroundScene.setSceneRect( rect );
}
void CustomView
::onZoomed( const QRectF & zoomRect
) {
double xScale = ( canvasRect.width() / zoomRect.width() );
double yScale = ( canvasRect.height() / zoomRect.height() );
resetTransform();
centerOn( zoomRect.center() );
scale( xScale, yScale );
mForegroundScene.setSceneRect( zoomRect.normalized() );
}
void CustomView::drawForeground( QPainter * pPainter, const QRectF & rect )
{
QGraphicsView::drawForeground( pPainter, rect );
mForegroundScene.render( pPainter, rect, QRectF(), Qt::IgnoreAspectRatio );
}
void CustomView::onSceneRectChanged( const QRectF & rect )
{
setSceneRect( rect );
mForegroundScene.setSceneRect( rect );
}
void CustomView::onZoomed( const QRectF & zoomRect )
{
QRectF canvasRect = rect();
double xScale = ( canvasRect.width() / zoomRect.width() );
double yScale = ( canvasRect.height() / zoomRect.height() );
resetTransform();
centerOn( zoomRect.center() );
scale( xScale, yScale );
mForegroundScene.setSceneRect( zoomRect.normalized() );
}
To copy to clipboard, switch view to plain text mode
where CustomView is derived from QGraphicsView and has a QGraphicsScene mForeGroundScene member variable. The onSceneRectChanged is connected to the shared scene's sceneRectChanged() signal, onZoomed() is a slot connected to a zoomed() signal emitted by the QWidget-based class that holds the CustomView instance in a layout.
Do I need to pass the mouse events to the dedicated scene first or will I need to implement the mouse controls in the view?
Good question, and I will eventually have to solve it because I will have the same need in my CustomView.
I am not sure how you would implement mouse interaction, except by doing it in the view itself. The foreground scene doesn't really have any views associated with it (including the one that owns it), so it won't receive any mouse events. I assume you could forward the view's events to the foreground scene or perhaps simply query the foreground scene for any items it contains at the given mouse position.
Perhaps Wysota has already solved this one too
P. S. There's actually more to this custom view than the above - I also implemented the drawBackground() method and added the optional ability to display a QPixmap as an underlay to data graphics and markers drawn above it in the main scene and the overlay scene. The purpose of this whole exercise was to implement a Qwt-style data plotting widget that uses a QGraphicsView as its central canvas. The background pixmap could represent a biological image, like a micrograph of a cell. I might want to overlay that with labels for different parts of the cell, line plots to show the concentration of certain chemicals, and so forth. The same scene data might be viewed in multiple windows, at different magnification scales or locations, so there are things that are scene-specific and other things that are view-specific. The mechanism suggested by Wysota seemed like a flexible way to support all those layers.
Bookmarks