0
votes

I have an application which shows some images in a grid and rest of the widgets in their respective positions. Something like thisimage Drawing inspiration from this i managed to solve keeping the aspect ratio of an image while resizing.

What are the issues:

  1. The QLabel widgets(image widgets) overlap if QMainWindow is shrinked. Check the image below shrinked
  2. The whole application is apparently not suited for different screens. Running this application on a laptop, layout is completely messed up.

What have i done:

Here is the MVCE code i have created

//ImageWidget.h

#ifndef IMAGEWIDGET_H
#define IMAGEWIDGET_H

#include <QLabel>
#include <QResizeEvent>
#include <QWidget>

class ImageWidget : public QLabel
{
    Q_OBJECT

public:
    explicit ImageWidget(QWidget* parent = nullptr);
    virtual QSize sizeHint() const;
    QPixmap scaledPixmap() const;
    virtual int widthForHeight(int height) const;

public slots:
    void setPixmap ( const QPixmap& p);
    void resizeEvent(QResizeEvent* ev);

private:
    QPixmap pix;
};

#endif // IMAGEWIDGET_H

ImageWidget.cpp

#include "imagewidget.h"



ImageWidget::ImageWidget(QWidget* parent) :
    QLabel(parent)
{
    setStyleSheet("QLabel{margin-left: 10px; border-radius: 25px; background: white; color: #4A0C46;}");

    QSizePolicy sizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    sizePolicy.setWidthForHeight(true);
    setSizePolicy(sizePolicy);

    setMinimumSize(sizeHint());
}



void ImageWidget::setPixmap (const QPixmap& p)
{
    pix = p;
    QLabel::setPixmap(scaledPixmap());
}




/* virtual */ int ImageWidget::widthForHeight(int height) const
{
    return pix.isNull() ? height * pix.height() / pix.width() : height;
}



QSize ImageWidget::sizeHint() const
{
    if(pix.width() != 0)
    {
        int h = this->height();
        return QSize(widthForHeight(h), h);
    }
    else
    {
        return QSize(300, 300);
    }
}



QPixmap ImageWidget::scaledPixmap() const
{
    auto scaled = pix.scaled(this->size() * devicePixelRatioF(), Qt::KeepAspectRatio, Qt::SmoothTransformation);
    scaled.setDevicePixelRatio(devicePixelRatioF());
    return scaled;
}



void ImageWidget::resizeEvent(QResizeEvent* )
{
    if (!pix.isNull())
    {
        QLabel::setPixmap(scaledPixmap());
    }
}

MainWindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QPushButton>
#include <QTableWidget>
#include "imagewidget.h"

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

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

protected:

    virtual void resizeEvent(QResizeEvent* event) override;

private:
    Ui::MainWindow *ui;
    ImageWidget* lbl1;
    ImageWidget* lbl2;
    ImageWidget* lbl3;
    ImageWidget* lbl4;

    QPushButton* btn1;
    QPushButton* btn2;
    QPushButton* btn3;
    QPushButton* btn4;

    QTableWidget* tableWidget;

};

#endif // MAINWINDOW_H

MainWindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QVBoxLayout>
#include <QTabWidget>
#include <QGridLayout>
#include <QHBoxLayout>
#include <QLabel>
#include <QTabBar>



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

    QVBoxLayout* mainLayout = new QVBoxLayout;
    QVBoxLayout* tabLay = new QVBoxLayout;
    QHBoxLayout* buttonLay = new QHBoxLayout;
    QGridLayout* gridLay = new QGridLayout;
    QHBoxLayout* dockLay = new QHBoxLayout;

    btn1 = new QPushButton(this);
    btn1->setText("Button1");
    btn2 = new QPushButton(this);
    btn2->setText("Button2");
    btn3 = new QPushButton(this);
    btn3->setText("Button3");
    btn4 = new QPushButton(this);
    btn4->setText("Button4");

    QTabWidget* tabView = new QTabWidget(this);
    tabView->addTab(new QWidget(), "Table");
    tabView->setMinimumSize(500, 300);
    tabView->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding);

    tableWidget = new QTableWidget(this);
    tableWidget->setFixedHeight(200);

    lbl1 = new ImageWidget(this);
    lbl2 = new ImageWidget(this);
    lbl3 = new ImageWidget(this);
    lbl4 = new ImageWidget(this);

    QPixmap lbl1Pix("1.png");
    QPixmap lbl2Pix("2.png");
    QPixmap lbl3Pix("3.png");
    QPixmap lbl4Pix("4.png");

    lbl1->setPixmap(lbl1Pix);
    lbl1->show();

    lbl2->setPixmap(lbl2Pix);
    lbl2->show();

    lbl3->setPixmap(lbl3Pix);
    lbl3->show();

    lbl4->setPixmap(lbl4Pix);
    lbl4->show();

    buttonLay->addWidget(btn1);
    buttonLay->addWidget(btn2);
    buttonLay->addWidget(btn3);
    buttonLay->addWidget(btn4);

    tabLay->addWidget(tabView);
    gridLay->addWidget(lbl1, 0, 0);
    gridLay->addWidget(lbl2, 0, 1);
    gridLay->addWidget(lbl3, 1, 0);
    gridLay->addWidget(lbl4, 1, 1);

    dockLay->addLayout(gridLay);
    dockLay->addLayout(tabLay);

    mainLayout->addLayout(dockLay);
    mainLayout->addLayout(buttonLay);
    mainLayout->addWidget(tableWidget);

    centralWidget()->setLayout(mainLayout);

    setMinimumSize(200,200);

    show();
}



MainWindow::~MainWindow()
{
    delete ui;
}



void MainWindow::resizeEvent(QResizeEvent * /*event*/)
{
    // get label dimensions
    int h = lbl1->height();
    int w = lbl1->widthForHeight(h);

    lbl1->setFixedWidth(w);
    lbl2->setFixedWidth(w);
    lbl3->setFixedWidth(w);
    lbl4->setFixedWidth(w);
}

Main.cpp

#include "mainwindow.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();

    return a.exec();
}

What do i want:

  1. Set a minimum size to the whole application so that the imagewidgets do not overlap.
  2. Make the whole app work on any PC or laptop screen with different resolutions.
  3. The imagewidgets should take up available space while keeping the aspect ratio of the images and the QTabWidget on the right should have a fixed size.

Maybe there is an easy solution but i am bit confused with Qt Layout management system.

EDIT1: Added the image with overlapping widgets

1
You didn't provide *.ui file so it's not completely MWE. Also for this size app I would implement UI code in C++.Konstantine Kozachuck
Can you show an image with your layout going wrong? The image you posted, looks fine to me.Chris
@Chris added an image with overlapping widgetsMarKS
@KonstantineKozachuck you don't need .ui file. It is empty. All the UI code is in Mainwindow.cpp. If you are trying to reproduce the bug just create a widget application and copy paste my code in there.MarKS

1 Answers

0
votes

Here is what I think is happening. When you set the pixmap like here:

QLabel::setPixmap(scaledPixmap());

The label will set the size of the images as the minimum size. And from that point on the label can not be resized any smaller.

The solution I have found around this is to set the following resize flags for the QLabel in the constructor:

QSizePolicy sizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
setSizePolicy(sizePolicy);

This way the QLabel will be resizable at all times. Or you might have to adapt the minimum width.

I am not sure if that is even it, but maybe it is a good start. Let me know what you make of this.