Qt: изменение размера метки QL, содержащей QPixmap, сохраняя при этом ее соотношение сторон



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



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



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



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



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

790   4  

4 ответов:

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

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

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 виджета, который содержит метку

Я отполировал этот подкласс отсутствует 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)

Я просто использовать 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);
    }
}

отлично работает для меня до сих пор. Добро пожаловать.

я попытался с помощью phyatt это AspectRatioPixmapLabel класс, но испытал несколько проблем:

  • иногда мое приложение вводило бесконечный цикл событий изменения размера. Я проследил это до звонка QLabel::setPixmap(...) внутри метода resizeEvent, потому что QLabel на самом деле называет updateGeometry внутри setPixmap, что может вызвать события изменения размера...
  • heightForWidth казалось, игнорируется содержащим виджет (a QScrollArea в моем случае), пока я не начал, устанавливая размер на этикетке, явный вызов policy.setHeightForWidth(true)
  • я хочу, чтобы метка никогда не росла больше, чем исходный размер пиксельного изображения
  • о 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();
    }
}

Comments

    Ничего не найдено.