How to get visible scene rectangle of QGraphicsView? - qt

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.

Related

Trying to paint a polygon on a graphics view, but have a problem getting the coordinates from inside the graphics view

I have a mainwindow.cpp and mainwindow.h file, a ui file containing the graphicsview. I load an image into a QGraphicsPixmapItem from a QImage. I add that pixmapitem named 'item' to a scene. And i set the scene with the following ui->graphicsView->setScene(scene);. I have a zoom out, a zoom in button and a fit to window button.
void MainWindow::on_actionZoom_In_triggered()
{
ui->graphicsView->scale(1.25,1.25);
//item->update(1.25,1.25,1.25,1.25);
//scene->update(1.25,1.25,1.25,1.25);
}
void MainWindow::on_actionZoom_Out_triggered()
{
ui->graphicsView->scale(0.75,0.75);
//item->update(0.75,0.75,0.75,07.5);
//scene->update(0.75,0.75,0.75,07.5);
}
void MainWindow::on_actionFit_Window_triggered()
{
ui->graphicsView->fitInView(scene->sceneRect(), Qt::KeepAspectRatio);
}
To get a point i use QPointF point = ui->graphicsView->mapFromParent(event->pos());
This only work when the image has not been zoomed out, zoomed in or fitted to window.
I have the feeling that it gets the points/coordinates from the situation when the image originally loaded. So the graphicsview scales, the item scales (i think), but i have the idea that the scene doesn't.
Either i want to call the method mousePressEvent from QGraphicsView (because that may work) or have the area from where the coordinates are collected from enlarged.
Steps:
Loading Image
Drawing Polygon (Picture not transformed)
Wrong coordinates, still in original area

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.

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.

Using QGraphicsView to display a local map

I'm trying to use QGraphicsView in order to display a map image and draw some items on top of it. The map boundaries are in a Cartesian coordinate system, for example NE(-500,200) to SW(600,-350). I know how to map image pixels <--> my coordinate system.
I would have to achieve the following:
Add a map image to the scene and tell Qt how to map the actual image pixels to scene coordinates.
Add graphic items at their real position, e.g. (-100,200)
Doing (2) is straightforward - simply add the item to the scene. How do I achieve (1)? what should I do after I call scene->addPixmap()?
Edit - A few clarifications:
I'm mapping an indoor area of a few hundred meters
The map will change at real-time in two ways:
The map gets bigger every few seconds
The graphic items move, change colors, etc.
Put the pixmap into a QGraphicsPixmapItem and place it in the scene.
Call setScale() to map the QGraphicsPixmapItem so 1 meter maps to 1 unit in the scene coordinate. ie. setScale(0.1) if 10 pixels in the pixmap equal 1 meter.
Update the pixmap and scale of the item as needed.
Call fitInView() to zoom to the pixmap.
Place other graphic items in the scene. Treat the units of the scene coordinate as meters.
...
Profit! :)

Resources