問題描述
我有一個(gè) QScrollArea,里面有一些按鈕,如圖所示.
I have a QScrollArea with some buttons in it, like shown on the picture.
布局的思路是:1. 左右鍵應(yīng)該用來滾動(dòng)太寬的按鈕
The idea of the layout is: 1. The left and right button should be used for scrolling the buttons when they are too wide
2.滾動(dòng)區(qū)域的按鈕數(shù)量可以動(dòng)態(tài)改變3. 應(yīng)利用任何可用空間盡可能擴(kuò)大滾動(dòng)區(qū)域.如果沒有這樣的空間存在導(dǎo)航按鈕應(yīng)該用于滾動(dòng).
2.The numbers of buttons in the scroll area can be changed dynamically 3. Any free space should be used to expand the scroll area as much as possible. If no such space exist navigation buttons should be used for scrolling.
使用我當(dāng)前的實(shí)現(xiàn),當(dāng)我增加按鈕時(shí),我有這個(gè):
With my current implementation when i increase the buttons i have this:
但是右邊有空閑空間,所以它應(yīng)該是這樣的:
But there is free space on the right, so this should look like:
例如,如果我再次增加到 10,那么應(yīng)該會(huì)出現(xiàn)滾動(dòng)條(因?yàn)椴季直恍〔考?.
If i increase once more to 10 for example, then scrollbar should appear( because the layout is constained by the widget ).
我想知道除了手動(dòng)調(diào)整小部件的大小之外是否還有其他方法(因?yàn)?ui 可以翻譯,按鈕可以更改大小提示,而且實(shí)際設(shè)計(jì)更復(fù)雜 :(
I want to know if there is any other way aside from manual resizing of the widgets( because ui can be translated and buttons can change size hint also the real design is more complicated :(
這是我對(duì) ScrollAreaTest 小部件的實(shí)現(xiàn):
Here is my implementation of the 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() );
}
這是包含問題的整個(gè) Qt 項(xiàng)目:https://drive.google.com/file/d/0B-mc4aKkzWlxQzlPMEVuNVNKQjg/edit?usp=sharing
And here is the whole Qt project containing the problem: https://drive.google.com/file/d/0B-mc4aKkzWlxQzlPMEVuNVNKQjg/edit?usp=sharing
推薦答案
基本步驟是:
保存按鈕的容器小部件(您的
CheckableButtonGroup
)必須設(shè)置一個(gè)QLayout::SetMinAndMaxSize
大小約束.然后它就會(huì)大到足以容納按鈕.它的大小策略無關(guān)緊要,因?yàn)槟皇菍⑺湃?QScrollArea
中,而不是放入另一個(gè)布局中.
The container widget that holds the buttons (your
CheckableButtonGroup
) must have aQLayout::SetMinAndMaxSize
size constraint set. Then it will be exactly large enough to hold the buttons. Its size policy doesn't matter, since you're simply putting it into aQScrollArea
, not into another layout.
滾動(dòng)區(qū)域需要根據(jù)它所持有的widget的大小來設(shè)置它的最大大小.默認(rèn)實(shí)現(xiàn)不這樣做,因此必須通過監(jiān)視嵌入式小部件的調(diào)整大小事件來實(shí)現(xiàn)它.
The scroll area needs to set its maximum size according to the size of the widget it holds. The default implementation doesn't do it, so one has to implement it by spying on resize events of the embedded widget.
下面的代碼是一個(gè)在 Qt 4.8 和 5.2 下都可以使用的最小示例.
The code below is a minimal example that works under both Qt 4.8 and 5.2.
// 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"
這篇關(guān)于QScrollArea 具有動(dòng)態(tài)變化的內(nèi)容的文章就介紹到這了,希望我們推薦的答案對(duì)大家有所幫助,也希望大家多多支持html5模板網(wǎng)!