QScrollArea具有动态变化的内容 [英] QScrollArea with dynamically changing contents

查看:298
本文介绍了QScrollArea具有动态变化的内容的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



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



2.按钮的数量在滚动区域可以动态改变
3.任何可用空间都应该尽可能地扩大滚动区域。如果没有这样的空间存在导航按钮应该用于滚动。



对于我当前的实现,当我增加按钮,我有这样:



但右侧有可用空间,因此这应该是这样:



如果我再次增加到10,例如,滚动条应该出现(因为布局是由窗口小部件固定的)。



我想知道如果有是除了手动调整窗口小部件之外的任何其他方式(因为ui可以翻译,按钮可以改变大小提示,真实设计也更复杂:(



这里是我的实现ScrollAreaTest小部件:

  #includeMainWidget.h

#include< QLineEdit> ;
#include< QVBoxLayout>
#include< QHBoxLayout>
#include< QScrollArea>
#include& lt; QPushButton>
#include< QDebug>
#includeButtonWidget.h

#includeCheckableButtonGroup.h

MainWidget :: MainWidget(QWidget * parent)
:QWidget父级),
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 :: Horizo​​ntal);
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(设置按钮计数);

buttonsContainer-> resize(m_buttons-> buttonsOptimalWidth(),buttonsContainer-> height());
m_buttons-> resize(m_buttons-> buttonsOptimalWidth(),m_buttons-> height());

// area-> resize(100,area-> height());
// area-> setHorizo​​ntalScrollBarPolicy(Qt :: ScrollBarAlwaysOff);
}

MainWidget ::〜MainWidget()
{
}

void MainWidget :: setButtonsCount()
{
m_buttons-> setButtonsCount(m_lineEdit-> text()。toInt());
}

这里是整个Qt项目包含的问题:
< a href =https://drive.google.com/file/d/0B-mc4aKkzWlxQzlPMEVuNVNKQjg/edit?usp=sharing =nofollow> https://drive.google.com/file/d/0B- mc4aKkzWlxQzlPMEVuNVNKQjg / edit?usp =共享

解决方案

基本步骤是:


  1. 保存按钮的容器小部件(您的 CheckableButtonGroup )必须有 QLayout :: SetMinAndMaxSize 大小约束集。然后,它将足够大,以保持按钮。它的大小策略并不重要,因为你只是把它放入 QScrollArea ,而不是另一个布局。


  2. 滚动区域需要根据其保存的窗口小部件的大小设置其最大大小。




p>下面的代码是一个在Qt 4.8和5.2下工作的最小示例。





  // https://github.com/KubaO/stackoverflown/tree/master/问题/ 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); //<<<基本
}
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
}
return QScrollArea :: eventFilter(obj,ev);
}
public:
AdjustingScrollArea(QWidget * parent = 0):QScrollArea {parent} {}
void setWidget(QWidget * w){
QScrollArea :: setWidget (w)。
//它发生QScrollArea已经过滤小部件事件,
//但这是一个实现细节,我们不应该依赖。
w-> installEventFilter(this);
}
};

class Window:public QWidget {
QGridLayout m_layout {this};
QLabel m_left {>>};
AdjustingScrollArea m_area;
QLabel m_right {<<};
QPushButton m_add {添加窗口小部件};
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();
}

#includemain.moc


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

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

If i increase once more to 10 for example, then scrollbar should appear( because the layout is constained by the widget ).

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 :(

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() );
}

And here is the whole Qt project containing the problem: https://drive.google.com/file/d/0B-mc4aKkzWlxQzlPMEVuNVNKQjg/edit?usp=sharing

解决方案

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.

// 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具有动态变化的内容的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆