Tomas Nekvinda
Tomas Nekvinda

Reputation: 544

Qt fitInView and resizing

I am trying to make a QGraphicsView with same width as height positioned in center of the window.

I created a ordinary QGraphicsView in Qt Designer and set minimal size, added some calculations that center the QGraphicsView into center of the main window and that set the same width as height. It uses only setGeometry. Than I created a QGraphicsScene with only one very long rectangle. I want the graphics scene to fit to view so I have used QGraphicsView::fitInView. Everything works OK, but the problem cames with resizing window.

When I increase height and width of the window everything also works fine. The QGraphicsView has a new position and a new size. When I reduce only a part of size of the window everything still works fine. But (finally) when I reduce the size of window to the possible minimum everything breaks. The rectangle in view has the right width (the same as without resizing, I have measured it with a ruler :) ), but a new margin is created and also QGraphicsView is not positioned and sized right (so it is not only the margin, but maybe also the setGeometry has no effect).

I have noticed, that the same thing happens when I call QGraphicsView::fitInView before using setGeometry.

It is getting me crazy, please help!

Here is some code:

void MainWindow::resizeEvent(QResizeEvent *e)
{
    int h = e->size().height(),
        w = e->size().width(),
        s;

    if(w > h) s = h-120;
    else s = w-120;

    ui->board->setGeometry((w-s)/2,(h-s)/2,s,s);

    int scaleWidth = ui->board->scene()->width(),
        scaleHeight = ui->board->scene()->height();

    ui->board->fitInView(QRectF(0, 0, scaleWidth, scaleHeight), Qt::KeepAspectRatio);

}

Here are images of what happens to QGraphicsView, the rectangle is red, view is blue:

this is OK this is broken

Upvotes: 3

Views: 23362

Answers (2)

Tim Seed
Tim Seed

Reputation: 5289

I needed to do the same thing but in a DialogForm...

I defined the Class header like this

#ifndef MAP_H
#define MAP_H

#include <QDebug>
#include <QDialog>
#include <QImage>
#include <QGraphicsPixmapItem>
namespace Ui {
class Map;
}

class Map : public QDialog
{
    Q_OBJECT

public:
    explicit Map(QWidget *parent = nullptr);
    ~Map();

private:
    Ui::Map *ui;
    QPixmap *m;         // This will load the Original Image
    QGraphicsScene* scene;  // This is the object passed to the Graphics Viewer
    QPixmap *scaledImage;  // This is the Scaled Image. It is created each resize from the Original Image (m)
    void resizeEvent(QResizeEvent *);

};

#endif // MAP_H

The Dialog Form is very simple and looks like this, it is a GraphicsView with OK/Cancel button.

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>Map</class>
 <widget class="QDialog" name="Map">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>675</width>
    <height>486</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>Dialog</string>
  </property>
  <layout class="QVBoxLayout" name="verticalLayout">
   <item>
    <widget class="QGraphicsView" name="graphicsView"/>
   </item>
   <item>
    <widget class="QDialogButtonBox" name="buttonBox">
     <property name="orientation">
      <enum>Qt::Horizontal</enum>
     </property>
     <property name="standardButtons">
      <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
     </property>
    </widget>
   </item>
  </layout>
 </widget>
 <resources/>
 <connections>
  <connection>
   <sender>buttonBox</sender>
   <signal>accepted()</signal>
   <receiver>Map</receiver>
   <slot>accept()</slot>
   <hints>
    <hint type="sourcelabel">
     <x>248</x>
     <y>254</y>
    </hint>
    <hint type="destinationlabel">
     <x>157</x>
     <y>274</y>
    </hint>
   </hints>
  </connection>
  <connection>
   <sender>buttonBox</sender>
   <signal>rejected()</signal>
   <receiver>Map</receiver>
   <slot>reject()</slot>
   <hints>
    <hint type="sourcelabel">
     <x>316</x>
     <y>260</y>
    </hint>
    <hint type="destinationlabel">
     <x>286</x>
     <y>274</y>
    </hint>
   </hints>
  </connection>
 </connections>
</ui>

The Implementation of the class is like this....

#include "map.h"
#include "ui_map.h"

Map::Map(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::Map)
{
    ui->setupUi(this);
    scene = new QGraphicsScene();
    QWidget::setMouseTracking(true);

    m = new QPixmap ("/usr/local/share/pixmaps/gpredict/maps/nasa-topo_1600.jpg");
}

Map::~Map()
{
    delete m;
    delete scene;
    delete ui;
}

void Map::resizeEvent(QResizeEvent *)
{
    qInfo() << "Resize event occurred";
    QSize gvs  = ui->graphicsView->size();
    QSize mvs  =  m->size();   // Just for interest

    qInfo() << "About to scale";
    qInfo() << "mvs is " << mvs;
    qInfo() << "gvs is " << gvs;
    QPixmap scaled_img = m->scaled(gvs, Qt::IgnoreAspectRatio);

    scene = new QGraphicsScene(this);
    scene->addPixmap(scaled_img);
    ui->graphicsView->setScene(scene);


}

The Image is now resized whenever the dialogForm is resized. It is (importantly) resampled from the original image, else there could be a loss of image quality.

I am only on day 2 of QT programming - trying to get my head around how it is wired up, but I hope this helps someone.

Upvotes: 0

Scott Griffiths
Scott Griffiths

Reputation: 684

I was trying to use QGraphicsView::fitInView with Qt::KeepAspectRatio, and was running into similar issues.
I found this answer helpful:

How to anchor QGraphicsView to a special point on a scene?

It seems the key is to manually set the scene's bounding rectangle. The following code worked for me:

MainWindow::MainWindow(QWidget *parent) : 
    QMainWindow(parent), ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    // Set up graphics view
    scene = new QGraphicsScene(this);
    drawMyWidget();
    scene->setSceneRect(-1.25, -1.25, 2.5, 2.5);    // your scene's bounding rect here...
    ui->graphicsView->setScene(scene);
    ui->graphicsView->show();
}

void MainWindow::resizeEvent(QResizeEvent *) {
    QRectF bounds = scene->itemsBoundingRect();
    bounds.setWidth(bounds.width()*0.9);         // to tighten-up margins
    bounds.setHeight(bounds.height()*0.9);       // same as above
    ui->graphicsView->fitInView(bounds, Qt::KeepAspectRatio);
    ui->graphicsView->centerOn(0, 0);
}

Upvotes: 10

Related Questions