C++ 内容动态变化的QScrollArea

C++ 内容动态变化的QScrollArea,c++,qt,desktop-application,qscrollarea,qlayout,C++,Qt,Desktop Application,Qscrollarea,Qlayout,我有一个QScrollArea,里面有一些按钮,如图所示。 布局的理念是: 1.当按钮太宽时,应使用左右按钮滚动按钮 2.滚动区域中的按钮数量可以动态更改 3.应使用任何可用空间尽可能扩大滚动区域。如果不存在此类空间,则应使用导航按钮进行滚动 在我当前的实现中,当我增加按钮时,我有: 但右侧有可用空间,因此应如下所示: 例如,如果我再次增加到10,那么滚动条应该出现(因为布局是由小部件控制的) 我想知道除了手动调整小部件的大小之外,是否还有其他方法(因为ui可以转换,按钮可以更改大小),但

我有一个QScrollArea,里面有一些按钮,如图所示。

布局的理念是: 1.当按钮太宽时,应使用左右按钮滚动按钮

2.滚动区域中的按钮数量可以动态更改 3.应使用任何可用空间尽可能扩大滚动区域。如果不存在此类空间,则应使用导航按钮进行滚动

在我当前的实现中,当我增加按钮时,我有:

但右侧有可用空间,因此应如下所示:

例如,如果我再次增加到10,那么滚动条应该出现(因为布局是由小部件控制的)

我想知道除了手动调整小部件的大小之外,是否还有其他方法(因为ui可以转换,按钮可以更改大小),但实际设计更复杂:(

下面是我对ScrollAreaTest小部件的实现:

#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() );
}
#包括“MainWidget.h”
#包括
#包括
#包括
#包括
#包括
#包括
#包括“ButtonWidget.h”
#包括“CheckableButtonGroup.h”
MainWidget::MainWidget(QWidget*父项)
:QWidget(父项),
m_滚动区域(0),
m_lineEdit(0),
m_按钮(0)
{
QVBoxLayout*mainLayout=新的QVBoxLayout(此);
QWidget*第一行=新的QWidget;
QHBoxLayout*firstRowLayout=新的QHBoxLayout(第一行);
QPushButton*左=新的QPushButton;
QPushButton*右=新的QPushButton;
m_按钮=新的可检查按钮组(Qt::水平);
m_按钮->设置策略(QSizePolicy::扩展,QSizePolicy::首选);
m_按钮->设置按钮计数(5);
m_按钮->设置样式表(“边框:无”);
QWidget*const buttonsContainer=新的QWidget;
QHBoxLayout*const buttonsContainerLayout=新的QHBoxLayout(buttonsContainer);
按钮容器布局->设置间距(0);
按钮ContainerLayout->setSizeConstraint(QLayout::SetMinAndMaxSize);
按钮容器布局->设置边距(0);
buttonsContainerLayout->addWidget(m_按钮,0,Qt::AlignLeft);
qDebug()按钮()[0]->size();
m_scrollArea=新的QScrollArea;
m_scrollArea->setContentsMargins(0,0,0,0);
m_scrollArea->setWidget(按钮容器);
m_scrollArea->SetWidgetResizeable(真);
m_scrollArea->setStyleSheet(“边框:1px纯蓝色”);
m_scrollArea->setSizePolicy(QSizePolicy::Expansing,QSizePolicy::Preferred);
firstRowLayout->addWidget(左,0,Qt::AlignLeft);
firstRowLayout->addWidget(m_scrollArea,1,Qt::AlignLeft);
firstRowLayout->addWidget(右、0、Qt::AlignLeft);
m_lineEdit=新的QLineEdit;
QPushButton*按钮=新的QPushButton;
QHBoxLayout*secondRowLayout=新的QHBoxLayout;
secondRowLayout->addWidget(m_lineEdit);
secondRowLayout->addWidget(按钮);
连接(按钮、信号(单击())、插槽(setButtonsCount());
mainLayout->addWidget(第一行,1,Qt::AlignLeft);
主布局->添加布局(第二行布局);
按钮->设置文本(“设置按钮计数”);
按钮容器->调整大小(m_按钮->按钮最佳宽度(),按钮容器->高度());
m_按钮->调整大小(m_按钮->按钮最佳宽度(),m_按钮->高度());
//面积->调整大小(100,面积->高度();
//area->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
}
MainWidget::~MainWidget()
{
}
void MainWidget::setButtonsCount()
{
m_按钮->设置按钮计数(m_lineEdit->text().toInt());
}
下面是包含问题的整个Qt项目:
基本步骤包括:

  • 保存按钮的容器小部件(您的
    CheckableButtonGroup
    )必须设置
    QLayout::SetMinAndMaxSize
    大小约束。然后它将足够大,可以容纳按钮。它的大小策略无关紧要,因为您只是将其放入
    qscrollara
    区域,而不是另一个布局

  • 滚动区域需要根据它所持有的小部件的大小来设置其最大大小。默认实现无法做到这一点,因此必须通过监视嵌入式小部件的调整大小事件来实现它

  • 下面的代码是在Qt4.8和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"
    

    //https://github.com/KubaO/stackoverflown/tree/master/questions/scrollgrow-21253755
    #包括
    #如果QT\u版本>=QT\u版本检查(5,0,0)
    #包括
    #恩迪夫
    类按钮组:公共QWidget{
    Q_对象
    QHBoxLayout m_layout{this};
    公众:
    按钮组(QWidget*parent=0):QWidget{parent}{
    m_layout.setSizeConstraint(QLayout::SetMinAndMaxSize);//宽度()+小部件()->宽度();
    }
    返回QScrollArea::eventFilter(obj,ev);
    }
    公众:
    AdjustingScrolArea(QWidget*parent=0):qScrolArea{parent}{
    void setWidget(QWidget*w){
    qscrolrea::setWidget(w);
    //碰巧QScrollArea已经过滤了小部件事件,
    //但这是一个我们不应该依赖的实现细节。
    w->installEventFilter(此);
    }
    };
    类窗口:公共QWidget{
    QGridLayout m_布局{this};
    QLabel m_左{“>>”};
    调整Crollarea m_区域;
    
    QLabel m_right{“已经这样做了。现在我正试图找出一种方法来获得一行间距,我的意思是跳过一行,并在这个“虚拟”空间后放置新按钮…
    QLayout::addStretch()
    QLayout::addstruct()
    应该可以做到这一点。