Reputation: 504
I created a small MVCE example to reproduce aspect ratio issue with an image on QGraphicsView
.
Building on this i realized the image scaling calculates the aspect ratio correctly but every time i resize QGraphicsView
it ignores my heightForWidth()
value (which actually returns the right height
).
ImageView.h
#include <QGraphicsView>
#include <QGraphicsScene>
#include <QResizeEvent>
#include <QWidget>
#include <QImage>
#include <QPixmap>
class ImageView : public QGraphicsView
{
Q_OBJECT
public:
ImageView(QWidget* parent = nullptr);
void setImage(const QImage& image);
virtual int heightForWidth(int width) const override;
protected:
virtual void resizeEvent(QResizeEvent *event) override;
private:
QGraphicsScene* m_scene;
QImage m_image;
QPixmap m_pixImage;
int m_rows;
int m_cols;
};
ImageView.cpp
#include "imageview.h"
#include <QDebug>
ImageView::ImageView(QWidget *parent) :
QGraphicsView{parent},
m_scene{new QGraphicsScene{this}},
m_rows{0},
m_cols{0}
{
setScene(m_scene);
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
QSizePolicy p(QSizePolicy::Minimum,QSizePolicy::Minimum);
p.setHeightForWidth(true);
setSizePolicy(p);
setFrameStyle(0);
setMouseTracking(true);
}
void ImageView::setImage(const QImage &image)
{
m_image = image;
m_cols = image.width();
m_rows = image.height();
m_pixImage = QPixmap::fromImage(image);
m_scene->addPixmap(m_pixImage);
fitInView(m_scene->itemsBoundingRect(),Qt::KeepAspectRatio);
}
/* virtual */ int ImageView::heightForWidth(int width) const
{
int height = (m_cols != 0) ? width * m_rows / m_cols : width;
qDebug() << "Height for width: " << height;
return height;
}
void ImageView::resizeEvent(QResizeEvent *event)
{
m_scene->clear();
qDebug() << "Graphics View: " << event->size();
QPixmap pxImg = m_pixImage.scaled(event->size(), Qt::KeepAspectRatio, Qt::SmoothTransformation);
if(!pxImg.isNull())
{
qDebug() << "Image: " << pxImg.size();
qDebug() << "Graphics View: " << event->size();
m_scene->addPixmap(pxImg);
}
fitInView(m_scene->itemsBoundingRect(),Qt::KeepAspectRatio);
QGraphicsView::resizeEvent(event);
}
MainWindow.h
#include <QMainWindow>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private:
Ui::MainWindow *ui;
};
MainWindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
ui->graphicsView->setImage(QImage("656780.png"));
}
MainWindow::~MainWindow()
{
delete ui;
}
Output:
Height for width: 586 // ideal height for the width to maintain aspect ratio (width should be 781)
Graphics View: QSize(782, 544) // instead height is set to 544 (width should be 725)
Image: QSize(725, 544) // scaling the image to the resize event size with aspect ratio
// turns out 725 is right for a width of 544
Graphics View: QSize(782, 544) // same here
As a result of the output my image is never scaled to the exact size of the QGraphicsView
on resizing.
How do i solve this? Is my calculation wrong? Or am i missing something?
Upvotes: 1
Views: 489
Reputation: 504
Okay after struggling a lot i realized i need not scale the image manually in QGraphicsView
. fitInView()
actually does this automatically. To answer my question, KeepAspectRatioByExpanding
is the answer.
void ImageView::resizeEvent(QResizeEvent *event)
{
fitInView(m_scene->itemsBoundingRect(),Qt::KeepAspectRatioByExpanding);
QGraphicsView::resizeEvent(event);
}
This scales the image along with the size of QGraphicsView
. One must keep in mind to allow scrollbars to show up if the image is upscaled or shrinked below its original size.
Upvotes: 1