首页 文章

Qt:调整包含QPixmap的QLabel的大小,同时保持其宽高比

提问于
浏览
56

我使用QLabel向用户显示更大,动态变化的QPixmap的内容 . 根据可用空间,使这个标签更小/更大会很好 . 屏幕尺寸并不总是与QPixmap一样大 .

如何修改QLabel的 QSizePolicysizeHint() 以调整QPixmap的大小,同时保持原始QPixmap的宽高比?

我无法修改QLabel的 sizeHint() ,将 minimumSize() 设置为零无效 . 在QLabel上设置 hasScaledContents() 允许增长,但是打破了宽高比...

子类化QLabel确实有帮助,但是这个解决方案只为一个简单的问题添加了太多的代码......

任何聪明的提示如何在没有子类化的情况下完成此任务?

4 回答

  • 73

    要更改标签大小,您可以为标签选择适当的大小策略,例如扩展或最小扩展 .

    您可以通过每次更改时保持其宽高比来缩放像素图:

    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

  • 27

    我已经完善了这个缺失的 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的回答)

  • 7

    我只是使用 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);
        }
    }
    

    到目前为止对我来说非常适合 . 别客气 .

  • 4

    我尝试使用phyatt的 AspectRatioPixmapLabel 类,但遇到了一些问题:

    • 有时我的应用程序进入了无限循环的调整大小事件 . 我在resizeEvent方法中追溯到 QLabel::setPixmap(...) 的调用,因为 QLabel 实际上在 setPixmap 内调用 updateGeometry ,这可能会触发调整大小事件...

    • heightForWidth 似乎被包含的小部件(在我的情况下为 QScrollArea )忽略,直到我开始为标签设置大小策略,显式调用 policy.setHeightForWidth(true)

    • 我希望标签永远不会超过原始像素图大小

    • QLabelminimumSizeHint() 的实现为包含文本的标签做了一些魔术,但总是将大小策略重置为默认值,所以我不得不覆盖它

    那就是说,这是我的解决方案 . 我发现我可以使用 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();
        }
    }
    

相关问题