1

I have made the following basic image viewer in Qt, however it does not behave as expected and for the love of what is holy, I cannot find out what the problem is. Basically, it's a QLabel for which I have set the movie as a jpeg/gif and then resized and centered it on the screen. The problem is, when it starts up, it neither resizes nor centers it on the screen, but instead it fills the window and stretches the image.

example:https://i.stack.imgur.com/YJf2x.jpg

If I put it in the QVBoxLayout, it's the same thing. However, if I perform a scaling/zoom (by pressing "+" or "-", as defined in the keyRelease event), it centers the image and resizes it perfectly.

example:https://i.stack.imgur.com/1uqd4.png

So the problem only seems to be when it loads the image, but I can't find out where. I know it must be something simple, but I've searched the Qt docs, google, tried combinations of commenting lines and adding different functions and I've come up with nothing.

By the way, the output from the bottom of the loadImage function prints the correct size and position, but it doesn't seem to respect them.

#include <QtGui>
#include "imageviewer.h"

ImageViewer::ImageViewer(QString imagePath)
{
    setWindowTitle(imagePath + " - Simple Image Viewer");
    currentImageSize=new QSize(0,0);

    fillScreen();

    imageLabel = new QLabel;
    imageLabel->setBackgroundRole(QPalette::Base);
    imageLabel->setScaledContents(true);

    QVBoxLayout* layout=new QVBoxLayout();
    layout->addWidget(imageLabel);

    QFrame* frame=new QFrame();
    frame->setLayout(layout);
    //setCentralWidget(frame);

    setCentralWidget(imageLabel);

    loadImage(imagePath);
}

void ImageViewer::loadImage(QString imagePath){
    currentImagePath=imagePath;
    open(imagePath);
    fitImage();
    centerImage();
    QTextStream out(stdout) ;

    //for debugging:
    out << QString("size: %1 %2 pos: %3 %4")
              .arg(imageLabel->width())
              .arg(imageLabel->height())
              .arg(imageLabel->x())
              .arg(imageLabel->y());
}

void ImageViewer::open(QString imagePath){
      if (!imagePath.isEmpty()) {
        QImage image(imagePath);

        currentImageSize=new QSize(image.size().width(),image.size().height());

        if (image.isNull()) {
            QMessageBox::information(this, tr("Image Viewer"),
                                     tr("Cannot load %1.").arg(imagePath));
            return;
        }

        imageLabel->resize(currentImageSize->width(),
                           currentImageSize->height());
        QMovie* movie=new QMovie(imagePath);
        imageLabel->setMovie(movie);
        movie->start();

        scaleFactor = 1.0;

        imageLabel->adjustSize();
      }
}

void ImageViewer::fitImage(){
    int windowHeight, windowWidth;
    int imageHeight, imageWidth;

    windowHeight = this->height();
    windowWidth = this->width();
    imageHeight = currentImageSize->height();
    imageWidth = currentImageSize->width();

    if(imageHeight > windowHeight || imageWidth > windowWidth){
        imageLabel->resize((windowHeight-40)*imageWidth/imageHeight, 
                            windowHeight-40);
    }
}

void ImageViewer::centerImage(){
    int windowHeight, windowWidth;
    int imageHeight, imageWidth;

    windowHeight = this->height();
    windowWidth = this->width();
    imageHeight = imageLabel->height();
    imageWidth = imageLabel->width();

    int x,y;
    x=(windowWidth-imageWidth)/2;
    y=(windowHeight-imageHeight)/2;
    imageLabel->move(x,y);
}

void ImageViewer::fillScreen(){
    this->showMaximized();
}

void ImageViewer::scaleImage(double factor)
{
    double newScale = scaleFactor + factor;

    if(newScale>MAX_SCALE || newScale<MIN_SCALE){
        return;
    }
    else{
        scaleFactor=newScale;
    }

    QTextStream out(stdout);
    imageLabel->resize(scaleFactor * currentImageSize->width(), 
                       scaleFactor * currentImageSize->height());

    out<< scaleFactor << " " 
       << imageLabel->height() << "," 
       << imageLabel->width() <<endl;

    centerImage();
}


void ImageViewer::keyReleaseEvent(QKeyEvent *event){
    if(event->key()==Qt::Key_Plus){
        scaleImage(SCALE_STEP);
    }
    if(event->key()==Qt::Key_Minus){
        scaleImage(0-(SCALE_STEP));
    }
}

for which the header is:

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QLabel>
#include <QMainWindow>

class ImageViewer : public QMainWindow
{
    Q_OBJECT

public:
    ImageViewer(QString imagePath);
    void open(QString imagePath);
    void loadImage(QString imagePath);
private:
    void fitImage();
    void centerImage();
    void fillScreen();
    void scaleImage(double);
    void adjustScrollBar(QScrollBar*,double);
    void keyReleaseEvent(QKeyEvent *);
private:
    QLabel* imageLabel;
    double scaleFactor;
    QSize* currentImageSize;
    QString currentImagePath;
    QString currentDir;
    QStringList neighbourImages;
    static const double MAX_SCALE=2.0;
    static const double MIN_SCALE=0.2;
    static const double SCALE_STEP=0.1;
};

#endif // MAINWINDOW_H

EDIT: this is the difference between the QLabel after it first loads and the QLabel after zoomed in once: diffchecker.com/1uDcb83

Nini Michaels
  • 341
  • 7
  • 17

1 Answers1

1

I believe the problem is that you are trying to calculate your sizes in the main window constructor. These sizes are not established at this point. You need to override QWidget::resizeEvent() (in ImageViewer) and do your sizing calculations there. That function is called after the geometry for the widget has been set.

Arnold Spence
  • 21,942
  • 7
  • 74
  • 67
  • Thanks for the input. I've done some debugging in the constructor, and it shows that the sizes are available; however, I've created a function foo() that loads the image and does all the computation, and called that after the show() call in main() and it still behaves the same. – Nini Michaels Feb 20 '12 at 20:43