2011-11-21 97 views
48

我使用QLabel將更大,動態變化的QPixmap的內容顯示給用戶。根據可用空間的不同,將此標籤更小/更大將會很好。屏幕尺寸並不總是和QPixmap一樣大。Qt:在保持寬高比的同時調整包含QPixmap的QLabel的大小

如何修改QLabel的QSizePolicysizeHint()以調整QPixmap的大小,同時保持原始QPixmap的縱橫比?

我無法修改QLabel的sizeHint(),因此將minimumSize()設置爲零不起作用。在QLabel設置hasScaledContents()允許增長,但打破了長寬比啄...

子類QLabel沒有幫助,但這種方法增加了只是一個簡單的問題,太多的代碼......

任何智能提示如何完成這個沒有子類?

+0

通過動態變化你是指像素數據還是維度? –

+0

我指的是當前佈局中'QLabel'的尺寸。 QPixmap應該保持其大小,內容和維度。此外,調整大小(實際上縮小)會「自動地」發生,以填充可用空間 - 最初爲「QPixmap」的大小。所有這些都是通過子類化來完成的...... – marvin2k

回答

58

爲了更改標籤尺寸,您可以爲標籤選擇適當的尺寸策略,如展開或最小展開。

您可以通過每次發生變化時保持其長寬比縮放像素圖:

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
+0

嗯是的,這基本上是我將子類「QLabel」的核心。但我認爲這個用例(在任意大小的Widgets中顯示具有任意大小的圖像)通常足以具有通過現有代碼實現的功能...... – marvin2k

+0

AFAIK默認情況下不提供此功能。實現你想要的最優雅的方式是繼承'QLabel'。否則,您可以在插槽/函數中使用我的答案的代碼,每次像素圖更改時都會調用它。 – pnezis

+1

因爲我希望'QLabel'能夠根據用戶調整'QMainWindow'的大小和可用空間自動擴展,所以我不能使用信號/插槽解決方案 - 我無法用這種方法建模_expanding_策略。 – marvin2k

23

我已經拋光了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的答案)

+1

謝謝,效果很好。我還會在''setPixmap()''方法中加入''QLabel :: setPixmap(pix.scaled(this-> size(), Qt :: KeepAspectRatio,Qt :: SmoothTransformation));''。 – Hyndrix

+0

你說得對。我假設你想存儲最高質量的pixmap版本,並且在調整/錨定標籤之前調用setPixmap。爲了減少代碼重複,我應該在'setPixmap'函數的尾部放置'this-> resize(width(),height());'。 – phyatt

+0

感謝分享。對於如何爲QPixmap設置「首選」大小,您是否有任何建議,以便在首次啓動應用程序時不會獲得最高分辨率? –

4

我試着用phyatt的AspectRatioPixmapLabel類,但在經歷了幾個問題:

  • 有時我的應用程序進入調整事件的無限循環。我追溯到QLabel::setPixmap(...)調用resizeEvent方法內,因爲QLabel實際上調用updateGeometry裏面setPixmap,這可能會觸發調整大小事件...
  • heightForWidth似乎是由含有小部件(在我的情況下,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

雖然對於包含此標籤的父控件和/或佈局尊重「heightForWidth」屬性的邊緣情況,此答案在包含此標籤的父控件和/或佈局不*遵守* 'heightForWidth'屬性。這是不幸的,因爲這個答案否則更可取[phyatt](https://stackoverflow.com/users/999943/phyatt)的[長期回答](https://stackoverflow.com/a/22618496/ 2809027)。 –

3

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

完美的作品對我來說至今。別客氣。

+1

剛剛使用這個,它的作品就像一個魅力!此外,非常巧妙地使用佈局管理器。應該是被接受的答案,因爲所有其他人在角落案件中都有缺陷。 – thokra

+0

儘管非直觀聰明,但這個答案解決了一個基本上不同的問題:「我們應該在大小已知的標籤和包含在該標籤中的像素圖之間添加多少內部填充以便保持寬高比那個pixmap?「其他答案解決了原始問題:「我們應該調整包含像素圖的標籤的大小以保持該像素圖的高寬比?」該答案要求以某種方式預先確定標籤的尺寸(例如,具有固定尺寸的策略),這在許多使用情況中是不希望的或者甚至是不可行的。 –

相關問題