Qt: изменение размера QLabel, содержащего QPixmap, с сохранением соотношения сторон - PullRequest
67 голосов
/ 21 ноября 2011

Я использую QLabel для отображения содержимого большего, динамически изменяющегося QPixmap для пользователя.Было бы неплохо сделать этот ярлык меньше / больше в зависимости от доступного места.Размер экрана не всегда такой большой, как у QPixmap.

Как я могу изменить QSizePolicy и sizeHint() QLabel для изменения размера QPixmap при сохранении соотношения сторон исходного QPixmap?

Я не могу изменить sizeHint() QLabel, установка нуля minimumSize() не помогает.Установка hasScaledContents() в QLabel позволяет расти, но нарушает соотношение сторон ...

Подклассы QLabel помогли, но это решение добавляет слишком много кода для простой проблемы ...

Какие-нибудь умные подсказки, как достигнуть этого без подклассов?

Ответы [ 5 ]

82 голосов
/ 21 ноября 2011

Чтобы изменить размер метки, вы можете выбрать подходящую политику размера для метки, такую ​​как расширение или минимальное расширение.

Вы можете масштабировать растровое изображение, сохраняя его соотношение сторон каждый раз, когда оно изменяется:

QPixmap p; // load pixmap
// get label dimensions
int w = label->width();
int h = label->height();

// set a scaled pixmap to a w x h window keeping its aspect ratio 
label->setPixmap(p.scaled(w,h,Qt::KeepAspectRatio));

Есть два места, где вы должны добавить этот код:

  • Когда растровое изображение обновляется
  • В resizeEvent виджета, который содержит метку
29 голосов
/ 24 марта 2014

Я отполировал этот недостающий подкласс QLabel. Это потрясающе и хорошо работает.

aspectratiopixmaplabel.h

#ifndef ASPECTRATIOPIXMAPLABEL_H
#define ASPECTRATIOPIXMAPLABEL_H

#include <QLabel>
#include <QPixmap>
#include <QResizeEvent>

class AspectRatioPixmapLabel : public QLabel
{
    Q_OBJECT
public:
    explicit AspectRatioPixmapLabel(QWidget *parent = 0);
    virtual int heightForWidth( int width ) const;
    virtual QSize sizeHint() const;
    QPixmap scaledPixmap() const;
public slots:
    void setPixmap ( const QPixmap & );
    void resizeEvent(QResizeEvent *);
private:
    QPixmap pix;
};

#endif // ASPECTRATIOPIXMAPLABEL_H

aspectratiopixmaplabel.cpp

#include "aspectratiopixmaplabel.h"
//#include <QDebug>

AspectRatioPixmapLabel::AspectRatioPixmapLabel(QWidget *parent) :
    QLabel(parent)
{
    this->setMinimumSize(1,1);
    setScaledContents(false);
}

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

int AspectRatioPixmapLabel::heightForWidth( int width ) const
{
    return pix.isNull() ? this->height() : ((qreal)pix.height()*width)/pix.width();
}

QSize AspectRatioPixmapLabel::sizeHint() const
{
    int w = this->width();
    return QSize( w, heightForWidth(w) );
}

QPixmap AspectRatioPixmapLabel::scaledPixmap() const
{
    return pix.scaled(this->size(), Qt::KeepAspectRatio, Qt::SmoothTransformation);
}

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

Надеюсь, это поможет! (Обновлено resizeEvent, за ответ @ dmzl)

10 голосов
/ 12 мая 2017

Я просто использую contentsMargin, чтобы исправить соотношение сторон.

#pragma once

#include <QLabel>

class AspectRatioLabel : public QLabel
{
public:
    explicit AspectRatioLabel(QWidget* parent = nullptr, Qt::WindowFlags f = Qt::WindowFlags());
    ~AspectRatioLabel();

public slots:
    void setPixmap(const QPixmap& pm);

protected:
    void resizeEvent(QResizeEvent* event) override;

private:
    void updateMargins();

    int pixmapWidth = 0;
    int pixmapHeight = 0;
};
#include "AspectRatioLabel.h"

AspectRatioLabel::AspectRatioLabel(QWidget* parent, Qt::WindowFlags f) : QLabel(parent, f)
{
}

AspectRatioLabel::~AspectRatioLabel()
{
}

void AspectRatioLabel::setPixmap(const QPixmap& pm)
{
    pixmapWidth = pm.width();
    pixmapHeight = pm.height();

    updateMargins();
    QLabel::setPixmap(pm);
}

void AspectRatioLabel::resizeEvent(QResizeEvent* event)
{
    updateMargins();
    QLabel::resizeEvent(event);
}

void AspectRatioLabel::updateMargins()
{
    if (pixmapWidth <= 0 || pixmapHeight <= 0)
        return;

    int w = this->width();
    int h = this->height();

    if (w <= 0 || h <= 0)
        return;

    if (w * pixmapHeight > h * pixmapWidth)
    {
        int m = (w - (pixmapWidth * h / pixmapHeight)) / 2;
        setContentsMargins(m, 0, m, 0);
    }
    else
    {
        int m = (h - (pixmapHeight * w / pixmapWidth)) / 2;
        setContentsMargins(0, m, 0, m);
    }
}

Пока у меня отлично работает. Не за что.

5 голосов
/ 31 декабря 2016

Я пытался использовать класс AspectRatioPixmapLabel в phyatt, но столкнулся с несколькими проблемами:

  • Иногда мое приложение входило в бесконечный цикл событий изменения размера.Я проследил это до вызова QLabel::setPixmap(...) внутри метода resizeEvent, потому что QLabel фактически вызывает updateGeometry внутри setPixmap, что может вызывать события изменения размера ...
  • heightForWidth, казалось, былоигнорируется содержащим виджет (a QScrollArea в моем случае), пока я не начал устанавливать политику размера для метки, явно вызывая policy.setHeightForWidth(true)
  • Я хочу, чтобы метка никогда не увеличивалась больше, чем исходный размер растрового изображения
  • QLabel Реализация minimumSizeHint() делает некоторую магию для меток, содержащих текст, но всегда сбрасывает политику размера к политике по умолчанию, поэтому мне пришлось перезаписать ее

сказал, вот мое решение.Я обнаружил, что могу просто использовать setScaledContents(true) и позволить QLabel обрабатывать изменение размера.Конечно, это зависит от содержащегося виджета / макета, соблюдающего heightForWidth.

aspectratiopixmaplabel.h

#ifndef ASPECTRATIOPIXMAPLABEL_H
#define ASPECTRATIOPIXMAPLABEL_H

#include <QLabel>
#include <QPixmap>

class AspectRatioPixmapLabel : public QLabel
{
    Q_OBJECT
public:
    explicit AspectRatioPixmapLabel(const QPixmap &pixmap, QWidget *parent = 0);
    virtual int heightForWidth(int width) const;
    virtual bool hasHeightForWidth() { return true; }
    virtual QSize sizeHint() const { return pixmap()->size(); }
    virtual QSize minimumSizeHint() const { return QSize(0, 0); }
};

#endif // ASPECTRATIOPIXMAPLABEL_H

aspectratiopixmaplabel.cpp

#include "aspectratiopixmaplabel.h"

AspectRatioPixmapLabel::AspectRatioPixmapLabel(const QPixmap &pixmap, QWidget *parent) :
    QLabel(parent)
{
    QLabel::setPixmap(pixmap);
    setScaledContents(true);
    QSizePolicy policy(QSizePolicy::Maximum, QSizePolicy::Maximum);
    policy.setHeightForWidth(true);
    this->setSizePolicy(policy);
}

int AspectRatioPixmapLabel::heightForWidth(int width) const
{
    if (width > pixmap()->width()) {
        return pixmap()->height();
    } else {
        return ((qreal)pixmap()->height()*width)/pixmap()->width();
    }
}
0 голосов
/ 27 января 2015

Спасибо, что поделились этим.Не могли бы вы подсказать, как я могу установить «предпочтительный» размер для QPixmap, чтобы он не принимал максимальное разрешение при первом запуске приложения?

...