Image doesn't fit graphics view frame
Asked Answered
R

5

16

I'm working on program which shows users some picture they select. I would like to fit this picture in QGraphicsView's frame, but the picture appears smaller than the frame.

So here's my code:

image = new QImage(data.absoluteFilePath()); // variable data is defined when calling this method
scn = new QGraphicsScene(this); // object defined in header
ui->graphicsView->setScene(scn);
scn->addPixmap(QPixmap::fromImage(*image));
ui->graphicsView->fitInView(scn->itemsBoundingRect(),Qt::KeepAspectRatio);

Here is some example of what is produced with the code above and what I want to get:

image showing produced and wanted looks

The picture's size is around 40 x 60 px when the frame is 200 x 400 px.

What could be wrong?

Raconteur answered 10/6, 2013 at 16:32 Comment(0)
R
24

Solution for my question is showEvent() for Dialog. This means that you can't call fitInView() before the form is showed, so you have to create showEvent() for dialog and the picture will be fitted into QGraphics View's frame.

And example code which you have to add into dialog's code:

void YourClass::showEvent(QShowEvent *) {
    ui->graphicsView->fitInView(scn->sceneRect(),Qt::KeepAspectRatio);
}
Raconteur answered 13/6, 2013 at 11:10 Comment(2)
I had an issue after this, how did you solved the white pixel border problem? I have a QDeclarativeView (which is a GraphicsView) and trying to fitInView for the scene()->itemsBoundingBox() which results in 1920x1080 pixels. Although it remains with a 5 pixels white border (because of the scene background color). If I do a setAlign(Qt::Left | Qt::Top) only the bottom right margin is displayed. Any hints?Vilberg
Different solution: Just run the function that sets the view after the .show().Richter
S
3

The reason you're not seeing your image as you want it is because the QGraphicsView function fitInView does not do what you think it does.

It ensures that the object fits inside the viewport, without any overlap of the borders of the view, so if your object was not in the view, calling fitInView will cause the view to move / scale etc to ensure that the object is completely visible. Also, if the viewport is too small for the area provided to fitInView, nothing will happen.

So, to get what you want, map the extents of the GraphicsView coordinates to the GraphicsScene and then set the image's scene coordinates to those. As @VBB said, if you stretch the image, it may change the aspect raio, so you can use scaledToWidth on the QPixmap.

Something like this: -

QRectF sceneRect = ui->graphicsView->sceneRect(); // the view's scene coords
QPixmap image = QPixmap::fromImage(*image);

// scale the image to the view and maintain aspect ratio
image = image.scaledToWidth(sceneRect.width());

QGraphicsPixmapItem* pPixmap = scn->addPixmap(QPixmap::fromImage(*image));

// overloaded function takes the object and we've already handled the aspect ratio
ui->graphicsView->fitInView(pPixmap);

You may find that you don't need the call to fitInView, if your viewport is in the right place and if you don't want it to look pixellated, use an image with a high resolution.

Swett answered 11/6, 2013 at 8:21 Comment(0)
W
1

You should handle resize event:

bool YourDialog::eventFilter(QObject *obj, QEvent *event)
{
    if (event->type() == QEvent::Show) {
        ui->conceptView->fitInView(conceptScene->sceneRect(), Qt::KeepAspectRatio);
    }

    if (event->type() == QEvent::Resize) {
        ui->conceptView->fitInView(conceptScene->sceneRect(), Qt::KeepAspectRatio);
    }
}
Wattage answered 26/2, 2015 at 11:0 Comment(0)
A
1

As the official documentation says, put fitinview() in resizeEvent()'s override:

Scales the view matrix and scrolls the scroll bars to ensure that the scene rectangle rect fits inside the viewport. rect must be inside the scene rect; otherwise, fitInView() cannot guarantee that the whole rect is visible.

This function keeps the view's rotation, translation, or shear. The view is scaled according to aspectRatioMode. rect will be centered in the view if it does not fit tightly.

It's common to call fitInView() from inside a reimplementation of resizeEvent(), to ensure that the whole scene, or parts of the scene, scales automatically to fit the new size of the viewport as the view is resized. Note though, that calling fitInView() from inside resizeEvent() can lead to unwanted resize recursion, if the new transformation toggles the automatic state of the scrollbars. You can toggle the scrollbar policies to always on or always off to prevent this (see horizontalScrollBarPolicy() and verticalScrollBarPolicy()).

Aggravate answered 9/7, 2022 at 6:41 Comment(0)
D
0

I think you should scale image. I do this and it works well:

QRect ref_Rect = QRect(x_pos, y_pos, Width, Length);
QGraphicsView* qGraph = new QGraphicsView(this);
qGraph->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
qGraph->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
qGraph->setGeometry(ref_Rect);

QGraphicsScene* scene = new QGraphicsScene(qGraph);
scene->setSceneRect(0, 0, ref_Rect.width(), ref_Rect.height());
qGraph->setScene(scene);

QImage *image = new QImage();
image->load("folder/name.png");
*image = image->scaled(ref_Rect.width(), ref_Rect.height(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation); 
QGraphicsPixmapItem* item = new QGraphicsPixmapItem(QPixmap::fromImage(*image));    

scene->addItem(item);
qGraph->show();
Deed answered 25/4, 2019 at 14:36 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.