问题描述
我有一个 QScrollArea,里面有一些按钮,如图所示.
I have a QScrollArea with some buttons in it, like shown on the picture.
布局的思路是:1. 左右键应该用来滚动太宽的按钮
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.滚动区域的按钮数量可以动态改变3. 应利用任何可用空间尽可能扩大滚动区域.如果没有这样的空间存在导航按钮应该用于滚动.
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.
使用我当前的实现,当我增加按钮时,我有这个:
With my current implementation when i increase the buttons i have this:
但是右边有空闲空间,所以它应该是这样的:
But there is free space on the right, so this should look like:
例如,如果我再次增加到 10,那么应该会出现滚动条(因为布局被小部件所包含).
If i increase once more to 10 for example, then scrollbar should appear( because the layout is constained by the widget ).
我想知道除了手动调整小部件的大小之外是否还有其他方法(因为 ui 可以翻译,按钮可以更改大小提示,而且实际设计更复杂 :(
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 :(
这是我对 ScrollAreaTest 小部件的实现:
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() );
}
这是包含问题的整个 Qt 项目: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
)必须设置一个QLayout::SetMinAndMaxSize
大小约束.然后它就会大到足以容纳按钮.它的大小策略无关紧要,因为您只是将它放入QScrollArea
中,而不是放入另一个布局中.
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.
滚动区域需要根据它所持有的widget的大小来设置它的最大大小.默认实现不这样做,因此必须通过监视嵌入式小部件的调整大小事件来实现它.
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.
下面的代码是一个在 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"
这篇关于QScrollArea 具有动态变化的内容的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!