I'm not 100 % sure how to achieve the precise layout requirements of the OP.
This didn't became better after fiddling a bit with stretch factors in the samples I have prepared.
So, my answer elaborates the IMHO two essential aspects which have to considered.
Setting up Stretch Factors
This is my experience about layout of widget sets which I first collected in OSF/Motif, then in GTK+ (which has the IMHO best layout management) and finally in Qt:
Don't try to fight against layout manager – you will end up in frustration (like Don Quixote). Instead, try to provide the right hints (however this is possible) to let the layout manager do something which does match your expectations most.
(Or just write an own which provides fixed widget positions and sizes to the underlying widget set. This can be enlighting to realize why the layout manager are that damn complicated to use.)
So, my first attempt was to set up the stretch factors right:
#include <QtWidgets>
int main(int argc, char **argv)
{
qDebug() << "Qt Version:" << QT_VERSION_STR;
QApplication app(argc, argv);
QImage img("cats.jpg");
QPixmap pixmap;
// setup GUI
QWidget winMain;
winMain.setWindowTitle("Layout Sample");
QVBoxLayout v;
QHBoxLayout h;
QLabel widget1("Widget1");
widget1.setFrameStyle(QLabel::Box | QLabel::Plain);
h.addWidget(&widget1, 1); // remark widget1 for growing (horizontally in HBox h)
QGridLayout g;
QLabel img1;
img1.setPixmap(QPixmap::fromImage(img));
g.addWidget(&img1, 0, 0);
QLabel img2;
img2.setPixmap(QPixmap::fromImage(img));
g.addWidget(&img2, 0, 1);
QLabel img3;
img3.setPixmap(QPixmap::fromImage(img));
g.addWidget(&img3, 1, 0);
QLabel img4;
img4.setPixmap(QPixmap::fromImage(img));
g.addWidget(&img4, 1, 1);
h.addLayout(&g, 0); // remark g for not growing (horizontally in HBox h)
v.addLayout(&h, 0); // remark h for not growing (vertically in VBox v)
QLabel widget2("Widget2");
widget2.setFrameStyle(QLabel::Box | QLabel::Plain);
widget2.setAlignment(Qt::AlignLeft | Qt::AlignTop);
v.addWidget(&widget2, 1); // remark widget2 for growing (vertically in VBox v)
QLabel widget3("Widget3");
widget3.setFrameStyle(QLabel::Box | QLabel::Plain);
widget3.setAlignment(Qt::AlignLeft | Qt::AlignTop);
v.addWidget(&widget3, 1); // remark widget3 for growing (vertically in VBox v)
winMain.setLayout(&v);
winMain.show();
// runtime loop
return app.exec();
}
Output:


This doesn't look that bad.
The Scaling Image Label
However, the image size in QLabel
doesn't change. To fix this, I recalled an old answer of mine SO: Qt - How to create Image that scale with window, and keeps aspect ratio?.
I removed all explicit stretching factors from the above sample and replaced the QLabel
s with images by instances of the derived ImageLabel
with resp. adjustment of QPixmap
size:
#include <QtWidgets>
class LabelImage: public QLabel {
private:
QPixmap _qPixmap, _qPixmapScaled;
public:
LabelImage(const QPixmap &qPixmap, QWidget *pQParent = nullptr):
QLabel(pQParent), _qPixmap(qPixmap)
{
QSizePolicy sizePolicy;
sizePolicy.setHorizontalPolicy(QSizePolicy::Ignored);
sizePolicy.setVerticalPolicy(QSizePolicy::Ignored);
sizePolicy.setHeightForWidth(true);
sizePolicy.setWidthForHeight(true);
setSizePolicy(sizePolicy);
}
virtual ~LabelImage() = default;
LabelImage(const LabelImage&) = delete;
LabelImage& operator=(const LabelImage&) = delete;
public:
//virtual QSize sizeHint() const override;
virtual int heightForWidth(int w) const override;
protected:
virtual void resizeEvent(QResizeEvent *pQEvent) override;
};
//QSize LabelImage::sizeHint() const { return _qPixmap.size(); }
int LabelImage::heightForWidth(int w) const
{
if (_qPixmap.width() == 0 || _qPixmap.height() == 0) return w;
return _qPixmap.height() * w / _qPixmap.width();
}
void LabelImage::resizeEvent(QResizeEvent *pQEvent)
{
QLabel::resizeEvent(pQEvent);
_qPixmapScaled = _qPixmap.scaled(pQEvent->size(), Qt::KeepAspectRatio);
QLabel::setPixmap(_qPixmapScaled);
}
int main(int argc, char **argv)
{
qDebug() << "Qt Version:" << QT_VERSION_STR;
QApplication app(argc, argv);
QImage img("cats.jpg");
QPixmap pixmap;
// setup GUI
QWidget winMain;
winMain.setWindowTitle("Layout Sample");
QVBoxLayout v;
QHBoxLayout h;
QLabel widget1("Widget1");
widget1.setFrameStyle(QLabel::Box | QLabel::Plain);
h.addWidget(&widget1);
QGridLayout g;
LabelImage img1(QPixmap::fromImage(img));
g.addWidget(&img1, 0, 0);
LabelImage img2(QPixmap::fromImage(img));
g.addWidget(&img2, 0, 1);
LabelImage img3(QPixmap::fromImage(img));
g.addWidget(&img3, 1, 0);
LabelImage img4(QPixmap::fromImage(img));
g.addWidget(&img4, 1, 1);
h.addLayout(&g);
v.addLayout(&h);
QLabel widget2("Widget2");
widget2.setFrameStyle(QLabel::Box | QLabel::Plain);
widget2.setAlignment(Qt::AlignLeft | Qt::AlignTop);
v.addWidget(&widget2);
QLabel widget3("Widget3");
widget3.setFrameStyle(QLabel::Box | QLabel::Plain);
widget3.setAlignment(Qt::AlignLeft | Qt::AlignTop);
v.addWidget(&widget3);
winMain.setLayout(&v);
winMain.show();
// runtime loop
return app.exec();
}
Output:



The layout management doesn't play that nicely (as expected – I didn't gave any stretch hint).
However, at least, the ImageLabel
- ensures scaling of image considering aspect-ratio correctly
- (tries to) resize the
QLabel
according to the image aspect-ratio (when possible).
The QSizePolicy
plays an important role. After having read the doc. downwards and upwards, I must admit I tried some settings which seemed to be promising after I found one which matched my expectations most.
IMHO, OPs solution is the right combination of the techniques in both samples.