Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Containing picture window resizing stops every few pixels



  • I have a simple dialog window with horizontal layout and QLable in it. QLable contains image. I use resize event to scale this image to fit window size.

    I used code from QT example. Header:

    #ifndef SCALEIMGDIALOG_H
    #define SCALEIMGDIALOG_H
    
    #include <QDialog>
    #include <QLabel>
    
    namespace Ui {
        class ScaleImgDialog;
    }
    
    class ScaleImgDialog : public QDialog
    {
        Q_OBJECT
    
    public:
        explicit ScaleImgDialog(QWidget *parent = 0);
        ~ScaleImgDialog();
    
    protected:
        void resizeEvent(QResizeEvent *event) override;
    
    private:
        Ui::ScaleImgDialog *ui;
        QPixmap testImg;
    };
    
    #endif
    

    and source file:

    #include <QDebug>
    #include "scaleImgDialog.h"
    #include "ui_scaleImgDialog.h"
    // main dialog window name is ScaleImgDialog ui_scaleImgDialog.h is generated automatically
    
    ScaleImgDialog::ScaleImgDialog(QWidget *parent) :
        QDialog(parent),
        ui(new Ui::ScaleImgDialog),
        testImg(":/images/testImg.jpeg")
    {
        ui->setupUi(this);
        setWindowFlags(windowFlags() ^ Qt::WindowContextHelpButtonHint);
        setWindowFlags(windowFlags() | Qt::WindowMaximizeButtonHint);
    }
    
    ScaleImgDialog::~ScaleImgDialog()
    {
        delete ui;
    }
    
    void ScaleImgDialog::resizeEvent(QResizeEvent *)
    {
        int newHeight = height();
        newHeight -= newHeight / 10;   // to prevent recursive resizing
        // Image heigh is much bigger then width so i use scaling by it
        ui->imgDisplayLabel->setPixmap(testImg.scaledToHeight(newHeight));
    }
    

    Size increase works well. But I faced next problem: when I try to make window smaller it doesn't work properly. Window shrinks a little and resizing stops. On next try it shrinks a little more and stops again and so on:
    alt text
    And second strange thing: if you don't release mouse button it is possible to resize window freely while it is bigger than size on beginning. Maximize window button and return to previous size also works well.
    alt text
    How to fix this and make window resing normal?


  • Moderators

    You're doing it wrong. Changing the image is rather expensive, and you can get a lot of resize events. What you should do instead is:

    1. Save the original picture in your class (as you'd done).
    2. Override the paintEvent method and paint the image as scaled there. Don't do rescaling in the resizeEvent, you're killing the responsiveness that way.


  • @kshegunov Thanks for your advice.

    So, look like I found an answer. If someone needs it:
    header

    class ScaleImgDialog : public QDialog {
        Q_OBJECT
    public:
        explicit ScaleImgDialog(QWidget *parent = 0);
        ~ScaleImgDialog();
    
    protected:
        void paintEvent(QPaintEvent *) override;
        void resizeEvent(QResizeEvent *) override;
    private:
        Ui::ScaleImgDialog *ui;
        QPixmap testImg;
    
        int imageWidth;
        int imageHeight;
    
        int widthOffset;
        int heightOffset;
    };
    

    source:

    ScaleImgDialog::ScaleImgDialog(QWidget *parent) :
        QDialog(parent),
        ui(new Ui::ScaleImgDialog),
        testImg(":/images/testImg.jpeg")
    {
        ui->setupUi(this);
        setWindowFlags(windowFlags() ^ Qt::WindowContextHelpButtonHint);
        setWindowFlags(windowFlags() | Qt::WindowMaximizeButtonHint);
    
        resizeEvent(nullptr);
    }
    
    ScaleImgDialog::~ScaleImgDialog()
    {
        delete ui;
    }
    
    void ScaleImgDialog::paintEvent(QPaintEvent *)
    {
        QPainter painter(this);
        painter.drawPixmap(widthOffset, heightOffset, imageWidth, imageHeight, testImg);
    }
    
    void ScaleImgDialog::resizeEvent(QResizeEvent *) {
        QSize winSize = size();
        imageHeight = testImg.height();
        imageWidth  = testImg.width();
    
        if (imageHeight  > winSize.height()) {
            double heightRatio = (double)winSize.height() / testImg.height();
            imageHeight = (int)(testImg.height() * heightRatio);
            imageWidth  = (int)(testImg.width()  * heightRatio);
        }
    
        if (imageWidth > winSize.width()) {
            double widthRatio = (double)winSize.width() / imageWidth;
            imageHeight = (int)(imageHeight * widthRatio);
            imageWidth  = (int)(imageWidth  * widthRatio);
        }
    
        widthOffset  = winSize.width()  > imageWidth  ? ((winSize.width()  - imageWidth)  / 2) : 0;
        heightOffset = winSize.height() > imageHeight ? ((winSize.height() - imageHeight) / 2) : 0;
    }
    

    So all size calculations are done in resizeEvent() (only when they needed) and drawing itself is happening in paintEvent(). This code keeps image size ratio and adds some "white spaces" to borders if necessary:
    it works


Log in to reply