fit QGraphicsScene to QGraphicsView - qt

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.

Related

How to remove Ghost Lines drawn in qgraphicsview

I am trying to make a simple program in which I have added a qgraphics scene and in this I have added a QGraphicsRectItem. I have implemented mouse press event, paint event, bounding rect. Now I have drawn a point on one side of rectangle because there can be multiple rectangle I can drop on screen so just to differentiate between them of different color. Now I can move my rectangle inside graphics seen and can increase the size of rectangle by moving it's one side at a time. The problem that I am facing is when I trying to draw point on one side of rectangle at the time of moving it, it leaves traces on graphics scene. can I remove the ghost lines?
This happens either because your boundingRect method isn't correct, or because you forgot to call prepareGeometryChange before making changes that affect the boundingRect result. Your boundingRect needs to include space for line widths, for example; that's a common mistake.

JavaFX: Rectangle with custom bounding rect and paint method

What I want to do:
In PySide, one could override the paintEvent() method of a QWidget to draw a custom widget. The bounding rect can be customized by overriding the boundingRect() method.
How does one do this in JavaFX? My goal is to create a custom Rectangle object, that draws itself smaller than it's bounding rect.
In context:
I'm creating an MS Paint clone in JavaFX. I'm working on the selection box that you use to select/move pixels around. I want the cursor to change to the appropriate resizing cursor when it is near the outside of the selection box.
However, the bounding rect is the same size as the selection box drawn on the screen, so the cursor only changes when it is on top of the box, but not when near. My solution is to set the bounding rect to larger than the actual selection box is, so the cursor change will occur. Then, override it's paintEvent() equivalent to draw a smaller selection box.
Thanks for your help.
I have a similar use case to you, and asked a similiar question here : Drawing transform independent layout bounds in JavaFX.
The JavaFX API is much higher level though than Java2D or PySide (I am assuming from your snippets, because I actually never heard of it ;) ), it does not allow you to override painting of Nodes, nor can you stop a Node from inheriting its parents transform.
This means that you need a seperate Group parallel to your content where you create the selection box and update it according to your needs (content changes etc.).
Example SceneGraph:
Scene
contentGroup
someShapeFromUser
selectionBoxGroup
selectionBoxOfSomeShapeFromUser

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.

qt get scrollview position

I have a QGraphicsView inside a Horizontal Layout. The QGraphicsScene contained in the QGraphics scene is pretty large (thousands of pixels), so scroll bars show up by default to allow me to scroll through the view.
Every time I update the scene inside the graphics scene, I delete the old scene, make a new one, populate it with objects, and call view->setScene(scene). When I do this, however, the scroll bars default to the top left corner of the QGraphicsView, instead of staying where they were at.
I tried saving the QGraphicsScene::sceneRect before destroying the scene, then doing a setSceneRect() afterwards to restore it, but that doesn't work since that only affects the scene itself, not the QGraphicsView that's displaying it. I also tried to do view->verticalScrollBar()->setValue(), but that doesn't appear to affect the scroll bars at all.
How can I access the scroll bars that are created for me by default, and set them to a value that was stored earlier?
Fixed by not deleting previous scene until after the new one is set.
e.g.
QGraphicsScene *previousScene = scene;
scene = new QGraphicsScene(0, 0, levelPlist.value("level_width").toInt(), levelPlist.value("level_height").toInt());
// config scene
QGraphicsView *view = ui->graphicsView;
view->setScene(scene);
delete previousScene;
Before I give a possible solution, I would highly recommend an approach that doesn't involve destroying your scene. If you're just clear()'ing your scene, you should be able to call setSceneRect() before clearing it, which will prevent the scene from automatically resizing its rect. When it's repopulated you can call setSceneRect() with a default-constructed QRect to give it control over the size of the rect once again.
If you really need to save/restore the scroll bars as stated, the following approach has worked for me in the past:
I've had to do something similar (for different reasons), and the best solution I've come up involves doing something like this:
Before clearing the scene, save off the positions of your vertical and horizontal scrollbars
Before reconstructing the scene, connect to the QScrollBar::rangeChanged() signal with a queued signal/slot connection. This signal should get fired after you've repopulated your scene, and it indicates that the scroll bars have been reconfigured by the view.
In your slot, disconnect from the rangeChanged() signal, and restore the scroll bar positions
Note that this is pretty much guaranteed to cause some flicker/jumpiness.

QGraphics Scene Zooming in and out

Here I am again worrying about how to Zoom in and out a QGraphicsPixmapItem in a graphics scene. I looked for a direct method for this but could not find any in graphics scene or in pix map. Can someone help me with this. Do I have to extend QGraphicsPixmapItem and implement methods for this.
Thanks again for help and I really do appreciate it.
~Tharanga
setScale() changes the size of the item, not the view scale of the scene. For a one item scene, it's effectively the same. But if you have more than one item in the scene, it changes the relation between items.
QGraphicsView::setTransform() should be used if you want to keep the item's relationship to the scene and other items.
QGraphicsPixmapItem inherits from QGraphicsItem, so it has all of that class's methods.
In particular, there's setScale that will change the item's scale factor (i.e. "zoom" it).
Look at the Transformations Example page for how this is done, and other transformations you can do.

Resources