2014-01-21 61 views
3

我有一個帶有一些按鈕的QScrollArea,如圖片所示。 enter image description here帶動態變化內容的QScrollArea

佈局的思路是: 1.左側和右側的按鈕應該被用於滾動按鈕的時候都太寬

2.數字在滾動區域的按鈕可以改變動態 3.應儘可能使用任何空閒空間來擴大滾動區域。如果沒有這樣的空間存在導航按鈕應該用於滾動。

以我目前的執行情況時,我提高了按鈕,我有這樣的: enter image description here

但在右邊的自由空間,所以這應該是這樣的: enter image description here

如果我增加一次,以10例如,那麼應該出現滾動條(因爲佈局是由小部件固定的)。

我想知道是否有任何其他方式除了小部件的手動調整大小(因爲UI可以翻譯和按鈕可以改變大小也暗示真正的設計更爲複雜:(

這裏是我的實現在ScrollAreaTest widget的:

#include "MainWidget.h" 

#include <QLineEdit> 
#include <QVBoxLayout> 
#include <QHBoxLayout> 
#include <QScrollArea> 
#include <QPushButton> 
#include <QDebug> 
#include "ButtonWidget.h" 

#include "CheckableButtonGroup.h" 

MainWidget::MainWidget(QWidget *parent) 
    : QWidget(parent), 
     m_scrollArea(0), 
     m_lineEdit(0), 
     m_buttons(0) 
{ 
    QVBoxLayout* mainLayout = new QVBoxLayout(this); 
    QWidget* firstRow = new QWidget; 
    QHBoxLayout* firstRowLayout = new QHBoxLayout(firstRow); 

    QPushButton* left = new QPushButton; 
    QPushButton* right = new QPushButton; 

    m_buttons = new CheckableButtonGroup(Qt::Horizontal); 
    m_buttons->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); 
    m_buttons->setButtonsCount(5); 
    m_buttons->setStyleSheet("border: none"); 

    QWidget* const buttonsContainer = new QWidget; 
    QHBoxLayout* const buttonsContainerLayout = new QHBoxLayout(buttonsContainer); 
    buttonsContainerLayout->setSpacing(0); 
    buttonsContainerLayout->setSizeConstraint(QLayout::SetMinAndMaxSize); 
    buttonsContainerLayout->setMargin(0); 
    buttonsContainerLayout->addWidget(m_buttons, 0, Qt::AlignLeft); 

    qDebug() << m_buttons->buttons()[ 0 ]->size(); 

    m_scrollArea = new QScrollArea; 
    m_scrollArea->setContentsMargins(0, 0, 0, 0); 
    m_scrollArea->setWidget(buttonsContainer); 
    m_scrollArea->setWidgetResizable(true); 
    m_scrollArea->setStyleSheet("border: 1px solid blue"); 
    m_scrollArea->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); 

    firstRowLayout->addWidget(left  , 0, Qt::AlignLeft); 
    firstRowLayout->addWidget(m_scrollArea, 1, Qt::AlignLeft); 
    firstRowLayout->addWidget(right  , 0, Qt::AlignLeft); 

    m_lineEdit = new QLineEdit; 
    QPushButton* button = new QPushButton; 
    QHBoxLayout* secondRowLayout = new QHBoxLayout; 
    secondRowLayout->addWidget(m_lineEdit); 
    secondRowLayout->addWidget(button); 

    connect(button, SIGNAL(clicked()), SLOT(setButtonsCount())); 

    mainLayout->addWidget(firstRow, 1, Qt::AlignLeft); 
    mainLayout->addLayout(secondRowLayout); 

    button->setText("Set buttons count"); 

    buttonsContainer->resize(m_buttons->buttonsOptimalWidth(), buttonsContainer->height()); 
    m_buttons->resize(m_buttons->buttonsOptimalWidth(), m_buttons->height()); 

    //area->resize(100, area->height()); 
    //area->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); 
} 

MainWidget::~MainWidget() 
{ 
} 

void MainWidget::setButtonsCount() 
{ 
    m_buttons->setButtonsCount(m_lineEdit->text().toInt()); 
} 

這裏是包含了存在問題的整個Qt工程: https://drive.google.com/file/d/0B-mc4aKkzWlxQzlPMEVuNVNKQjg/edit?usp=sharing

回答

6

的基本步驟是:

  1. 容納按鈕的容器小部件(您的CheckableButtonGroup)必須具有QLayout::SetMinAndMaxSize大小約束集。那麼它將會足夠大以容納按鈕。它的尺寸政策並不重要,因爲您只需將其放入QScrollArea,而不是放入其他佈局。

  2. 滾動區域需要根據其保存的窗口小部件的大小設置其最大大小。默認實現不會這樣做,所以必須通過監視嵌入的小部件的調整大小事件來實現它。

下面的代碼是一個在Qt 4.8和5.2下工作的最簡單的例子。

Screenshot with two buttons

Screenshot with multiple buttons

// https://github.com/KubaO/stackoverflown/tree/master/questions/scrollgrow-21253755 
#include <QtGui> 
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0) 
#include <QtWidgets> 
#endif 

class ButtonGroup : public QWidget { 
    Q_OBJECT 
    QHBoxLayout m_layout{this}; 
public: 
    ButtonGroup(QWidget * parent = 0) : QWidget{parent} { 
     m_layout.setSizeConstraint(QLayout::SetMinAndMaxSize); // <<< Essential 
    } 
    Q_SLOT void addButton() { 
     auto n = m_layout.count(); 
     m_layout.addWidget(new QPushButton{QString{"Btn #%1"}.arg(n+1)}); 
    } 
}; 

class AdjustingScrollArea : public QScrollArea { 
    bool eventFilter(QObject * obj, QEvent * ev) { 
     if (obj == widget() && ev->type() == QEvent::Resize) { 
     // Essential vvv 
     setMaximumWidth(width() - viewport()->width() + widget()->width()); 
     } 
     return QScrollArea::eventFilter(obj, ev); 
    } 
public: 
    AdjustingScrollArea(QWidget * parent = 0) : QScrollArea{parent} {} 
    void setWidget(QWidget *w) { 
     QScrollArea::setWidget(w); 
     // It happens that QScrollArea already filters widget events, 
     // but that's an implementation detail that we shouldn't rely on. 
     w->installEventFilter(this); 
    } 
}; 

class Window : public QWidget { 
    QGridLayout   m_layout{this}; 
    QLabel    m_left{">>"}; 
    AdjustingScrollArea m_area; 
    QLabel    m_right{"<<"}; 
    QPushButton   m_add{"Add a widget"}; 
    ButtonGroup   m_group; 
public: 
    Window() { 
     m_layout.addWidget(&m_left, 0, 0); 
     m_left.setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Preferred); 
     m_left.setStyleSheet("border: 1px solid green"); 

     m_layout.addWidget(&m_area, 0, 1); 
     m_area.setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred); 
     m_area.setStyleSheet("QScrollArea { border: 1px solid blue }"); 
     m_area.setWidget(&m_group); 
     m_layout.setColumnStretch(1, 1); 

     m_layout.addWidget(&m_right, 0, 2); 
     m_right.setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); 
     m_right.setStyleSheet("border: 1px solid green"); 

     m_layout.addWidget(&m_add, 1, 0, 1, 3); 
     connect(&m_add, SIGNAL(clicked()), &m_group, SLOT(addButton())); 
    } 
}; 

int main(int argc, char *argv[]) 
{ 
    QApplication a{argc, argv}; 
    Window w; 
    w.show(); 
    return a.exec(); 
} 

#include "main.moc" 
+0

我有一個類似滾動區域和我想知道如果它是可以具有這些的按鈕佈置4個按鈕/行(如我看到上面的例子)。 [?] –

+0

@groenhen確定可以按照你想要的方式安排它們。 –

+0

已經做到了。現在我試圖找出一種方法來獲得一行間隔,我的意思是跳過一行,並在這個「虛擬」空間之後放置新的按鈕... –