c++ - 内容动态变化的QScrollArea

标签 c++ qt desktop-application qscrollarea qlayout

我有一个带有一些按钮的 QScrollArea,如图所示。 enter image description here

布局的思路是: 1. 左右键太宽时应使用左右键滚动

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

在我当前的实现中,当我增加按钮时,我有这个: enter image description here

但是右边有空闲空间,所以这应该是这样的: enter image description here

例如,如果我再次增加到 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() );
}

这是包含问题的整个 Qt 项目: https://drive.google.com/file/d/0B-mc4aKkzWlxQzlPMEVuNVNKQjg/edit?usp=sharing

最佳答案

基本步骤是:

  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"

关于c++ - 内容动态变化的QScrollArea,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21253755/

相关文章:

C++读取字节问题

c++ - 高性能 QImage 输出显示

桌面创建桌面窗口?

qt - 从 qml 中的 .txt 或 .csv 文件读取一行(Qt Quick)

类似于Android的Java桌面开发框架?

python - 如何通过python google drive api创建一个新文件夹以及MediaFileUpload的用途是什么?

c++ - vector 的数据如何对齐?

C++ 为多维数组赋值

c++ - winsock2中发送其他数据类型

java - 桌面应用程序的推荐技术选择