0

I'm trying to keep the Aspect Ratio of the main window when it's resized, unfortunately I get flickering while resizing.

The code:

// maindialog.h

#ifndef MAINDIALOG_H
#define MAINDIALOG_H

#include <QDialog>
#include <QLabel>
#include <QSize>
#include <QImage>
#include <QPixmap>
#include <QSlider>
#include <QResizeEvent>

// aspect ratio
#define ASPECT_HEIGHT_9(width) ( ( width / 16 ) * 9 )
#define ASPECT_HEIGHT_10(width) ( ( width / 16 ) * 10 )

#define ASPECT_WIDTH_9(height) ( ( height / 9 ) * 16 )
#define ASPECT_WIDTH_10(height) ( ( height / 10 ) * 16 )

// padding
#define PADDING 5
#define X_2_PADDING 10

// main window
#define DEFAULT_WIDTH 1280
#define DIMENSIONS QSize( DEFAULT_WIDTH, ASPECT_HEIGHT_9(DEFAULT_WIDTH) )

// video
#define VIDEO_SCALE_FACTOR 0.8
#define VIDEO_WIDTH DEFAULT_WIDTH * VIDEO_SCALE_FACTOR
#define VIDEO_HEIGHT ASPECT_HEIGHT_10(VIDEO_WIDTH)

// seeker
#define VIDEO_SEEKER_HEIGHT 20

class MainDialog : public QDialog
{
    Q_OBJECT

public:
    MainDialog(QWidget *parent = 0);
    ~MainDialog();

signals:
    void resized(QSize size);

private slots:
    void on_seeker_valueChanged(int value);
    void on_resize(QSize size);

protected:
    void resizeEvent(QResizeEvent * event);

private:
    QLabel *video;
    QSlider *seeker;
};

#endif // MAINDIALOG_H

// maindialog.cpp

#include "maindialog.h"

MainDialog::MainDialog(QWidget *parent)
    : QDialog(parent),
      video(new QLabel(this)),
      seeker(new QSlider(Qt::Horizontal, this))
{
    connect(this, SIGNAL(resized(QSize)), this, SLOT(on_resize(QSize)));
    connect(seeker, SIGNAL(valueChanged(int)), this, SLOT(on_videoSeeker_valueChanged(int)));
    video->move(PADDING, PADDING);
    video->setScaledContents(true);
    emit resized(DIMENSIONS);
}

void MainDialog::on_resize(QSize size){
    resize(size);

    // Video
    int width = size.width() * VIDEO_SCALE_FACTOR;
    video->resize(width, ASPECT_HEIGHT_10(width));
    QImage image(video->size(), QImage::Format_RGB888);
    video->setPixmap(QPixmap::fromImage(image));

    // seeker
    seeker->move(video->x() + PADDING, video->y() + video->height() + PADDING);
    seeker->resize(video->width() - X_2_PADDING, VIDEO_SEEKER_HEIGHT);
}

void MainDialog::on_seeker_valueChanged(int value){
    // implement with opencv
}

void MainDialog::resizeEvent(QResizeEvent *event){
    QSize _old = event->oldSize();
    QSize _new = event->size();
    QSize updated;
    updated = _old.width() != _new.width() ?
              QSize( _new.width(), ASPECT_HEIGHT_9( _new.width() ) ) :
              QSize( ASPECT_WIDTH_9( _new.height() ), _new.height() );

    emit resized(updated);
}

MainDialog::~MainDialog() {
    delete video;
    delete seeker;
}

This approach can't be right! Flickering aside, it doesn't seem like a good idea to resize the window from within the resizeEvent(QResizeEvent *event).

Question:

How do I go about(intelligently) keeping the Aspect Ratio when the window is resized?

Is there any way of completely overriding the resize operation?

Dima Maligin
  • 1,386
  • 2
  • 15
  • 30
  • Indeed it doesn't. I'm not sure if there's a clean way. It even seems like there should be a resizeMode that respects the aspect ratio. I think it would be reasonable to start a QTimer with a small timeout (50ms or so?). Restart the value within on_resize() so it only timeouts after (Presumably) the resize is done. Then you can fix the ratio. The caveat is, which one to use as the base? The change only the width or only the height, which would yield pretty bad results I'd think. – kiss-o-matic Dec 16 '14 at 21:10
  • A quick Google also showed me this. Haven't tested it, but have a gander. http://stackoverflow.com/questions/452333/how-to-maintain-widgets-aspect-ratio-in-qt – kiss-o-matic Dec 16 '14 at 21:11
  • @kiss-o-matic yes I saw that answer(even tried it) not much help there unfortunately. Won't the timer cause more flickering? since the delay will be seen as an incorrect size. – Dima Maligin Dec 16 '14 at 21:16
  • My approach (that I only did in my head - it may totally suck) is to only resize after the *last* resizeEvent is called. IE, the user grabs the end of the dialog and resizes it. Another way (which doesn't qualify as inteligent) but might alleviate the flickering is keep a count of how many time resizeEvent has been called, and force the ratio only after n calls. Still ghetto, but will probably result in less flicker. – kiss-o-matic Dec 16 '14 at 21:26
  • @kiss-o-matic Well I tried your suggestion and there is no flickering but it doesn't feel natural. – Dima Maligin Dec 16 '14 at 21:59
  • Can you reimplement QResizeEvent and do the paint yourself? You'll no doubt need to look at the source code, which is likely substantial, but it's about the only way I could think of. On QResizeEvent(), figure out which dimension changed (or pick one if both did) and calculate the other? – kiss-o-matic Dec 16 '14 at 22:56

0 Answers0