How to get visible scene rect for QGraphicsView - qt

Imagine QGraphicsView is set with the scene that is twice as wider as view's width. sceneRect() will return the whole scene rect. I'd like to get the rect representing the half of the scene with respect to scrollbars' positions.

Get the viewport rectangle with the graphicsView->viewport()->rect() and map it to the scene space with the graphicsView->mapToScene().

I am not totally sure which rectangle you exactly need (this depends from what you want to do) but something like graphicsView->viewport()->contentsRect() or graphicsView->viewport()->geometry() should work.

Related

fit QGraphicsScene to QGraphicsView

I'm trying to draw a stacked bar graph on Qt, i followed the tutorial on the documentation but when i try to put the graph inside a QGraphicsView i get a lo of unused space and can't manage to make the scene fit the view.
My code is the same as the documentation one plus the following to make the scene show up in the view:
QGraphicsScene *scene = new QGraphicsScene(this);
scene->addWidget(chartView);
ui->view->setScene(scene);
And what i get is this
As you can see there is a lot of unused space and it makes the text disappear, i wanted to make the graph fit the view but i can't seem to find a way to do so.
I tried in many different ways using
ui->view->ensureVisible ( scene->sceneRect() );
ui->view->fitInView( scene->sceneRect(),Qt::KeepAspectRatio);
and
ui->view->setSceneRect(0,0,ui->view->frameSize().width(),ui->view->frameSize().height());
but nothing seems to work (the second solution just moves the graph to the top left)
As per the comment... the real issue is the basic sizing of chartView rather than anything to do with QGraphicsView or QGraphicsScene.
When a QWidget is added to a QGraphicsScene the resulting QGraphicsProxyWidget will generally honour the size hint and policy of that widget.
In addition, though, the QGraphicsScene will set the scene rect to the bounding rectangle of all scene items and the QGraphicsView will then position the scene according to whatever viewport anchor is in force. The end result can be visually misleading if the scene has a complex set of items or has a bounding rectangle smaller than that displayed within the GraphicsView.
So if a widget does look odd when added to a QGraphicsScene it's normally a good idea to test by just showing it as a top level window on the desktop and make sure it behaves as expected before going any further.

expand qgraphicsrectitem to cover complete scene and expand all children's in same proportion

I have created a QGraphicsView with a scene set on it with QGraphicsRectItem in it.
[fig-1]
I want that when I double click on the green rectangle marked with thick black border, the scene gets filled with only this rectangle and all its children also get expanded in same proportion.
So, when I double click , I should see something like this in complete view:
I have handled the double click event but do not know how to handle this.
Also, when I double click again, I get back to the previous state (as shown in fig-1)
As the documentation states for QGraphicsView::fitInView
Ensures that item fits tightly inside the view, scaling the view according to aspectRatioMode.
So, assuming pView is your QGraphicsViewand thisis the rectangle you want to view, call fitInView from the overloaded double click event of QGraphicsRectItem: -
pView->fitInView(this);
Based on the comments that only the rect and its children should be visible, one option to guarantee this would be, on double-click, to create a separate scene, move the rect to the new scene and switch the view to the new scene.

How to have QGraphicsScene not centered in QGraphicsView

How can I manualy position a QGraphicsScene inside the QGraphicsView, because the default is always centered, but I want to position it by myself.
Call the centerOn function of QGraphicsView
Scrolls the contents of the viewport to ensure that the scene coordinate pos, is centered in the view.
Alternatively, if you want to specify a rect of the area in the scene to be visible, you can use fitInView.

x,y point shifts when the width is reduced below 200 in QGraphicsScene

I have created a QGraphicsScene
scene = new QGraphicsScene(0,0,200,200);
and draw a line scene.addLine(0,0,100,100,pen); and I got the line correctly drawn from (0,0) to (100,100).
When I change the code to
scene = new QGraphicsScene(0,0,150,200);
And draw the same line scene.addLine(0,0,100,100,pen);, Its x,y point shifts to the right side by 50 pixels. Why does this happen? How to avoid this?
By default, the scene rectangle is centered in the QGraphicsView when it is smaller than the view.
You can use QGraphicsView::setAlignment to change that.
Since the view preferred size, returned by QGraphicsView::sizeHint() is also the scene size, you can adjust the view to fit exactly the scene with:
view->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
which tells the layout to only use sizeHint() to calculate the size of the widget.
Or if the view is not inside a layout, you'll have to set the size with
view->setFixedSize(view->sizeHint());
each time you change the scene rect size.

How to get visible scene rectangle of QGraphicsView?

I'm displaying a map built as rectangle of QGraphicsPixmapitem items (each item stands for one map tile). Because my map is quite large (around 30 MB of PNG files) I want to be able to load pixmaps on demand only when they're visible for user in QGraphicsView and unload when they became invisible.
Is there any way to figure out visible scene rectangle?
This gives you the visible scene rectangle:
sceneRect = graphicsView.mapToScene(graphicsView.rect()).boundingRect()
In case there is a shear or rotation transformation present it gives you the bounding rectangle of the visible scene area. If you do not have such transformations (only shift or zoom) the returned rectangle is the exact scene area.
Now for your real problem of efficiently display a huge tiles map in a scene? You could load the tiles in background and first evaluate if your Qt framework isn't already optimized for big pixmap that are outside the visible range. 30 MB also doesn't sound so big that it wouldn't fit into memory.
QGraphicsView inherits the QWidget::geometry() function. You can use this to determine its location and size within its parent widget. (Outside of its constructor)
The QGrapicsScene can be larger than the QGraphicsView. The default QGraphicsView will add horizontal and vertical scroll bars to house the QGraphicsScene. I imagine you would like to do something like this:
//create a QGraphicsScene (for this example *scene) that is the size of your entire map.
QGraphicsScene *scene=new QGraphicsScene(0,0,mapWidth,mapHeight);
//create a QGraphicsView* named view that is the size of your visible area
//I'm assuming visibleHeight and visibleWidth do not change (this is your viewing window)
QGraphicsView *view=new QGraphicsView(0,0,visibleWidth,visibleHeight);
view->setScene(scene);
Have the user control the x and y position of the scene that triggers some custom signal like sceneMoved(int,int). Before you redraw the scene, call a slot to check the new position of the scene:
connect(this,SIGNAL(sceneMoved(int,int)),this,SLOT(drawScene(int,int)));
void SomeClass::drawScene(int newX, int newY){
//if you already have a pointer to the scene do this, or call
//QGraphicsView::scene();
int oldX=scene->geometry()->x();
int oldY=scene->geometry()->y();
//now that you have your oldX, oldY, newX, and newY, visibleWidth, visibleHeight
//you can determine what you need to redraw, what you need to delete, and what can stay
}
There is still a lot of if..else, but you get the point. I suggest trying to segment your map into squares the size of your visible area.

Resources