QScrollArea with dynamically changing contents

前端 未结 1 1894
一生所求
一生所求 2020-12-01 17:36

I have a QScrollArea with some buttons in it, like shown on the picture. \"enter

The i

相关标签:
1条回答
  • 2020-12-01 18:05

    The essential steps are:

    1. The container widget that holds the buttons (your CheckableButtonGroup) must have a QLayout::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 a QScrollArea, not into another layout.

    2. 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.

    The code below is a minimal example that works under both Qt 4.8 and 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 讨论(0)
提交回复
热议问题