QScrollArea not working as expected with QWidget a

2020-07-13 08:34发布

问题:

So I have this QFrame which is the parent widget (represented by this in the code). In this widget, I want to place a QWidget at 10 px from top (and 10 px from bottom, as a result of which it will have a height of 140px, whereas parent is 160px). The QWidget will have a number of custom buttons inside it in a vertical layout, in a scroll area, so that when the height of the buttons combined exceeds the QWidget's height (140px), scroll sets in automatically. Because the scroll is not for the entire parent widget, but only for a child widget, the scroll should apply only to the child widget here. Here is my code:

//this is a custom button class with predefined height and some formatting styles
class MyButton: public QPushButton
{

public:
    MyButton(std::string aText, QWidget *aParent);

};

MyButton::MyButton(std::string aText, QWidget *aParent): QPushButton(QString::fromStdString(aText), aParent)
{
    this->setFixedHeight(30);
    this->setCursor(Qt::PointingHandCursor);
    this->setCheckable(false);
    this->setStyleSheet("background: rgb(74,89,98);   color: black; border-radius: 0px; text-align: left; padding-left: 5px; border-bottom: 1px solid black;");
}

//this is where I position the parent widget first, and then add sub widget
this->setGeometry(x,y,width,160);
this->setStyleSheet("border-radius: 5px; background:red;");

//this is the widget which is supposed to be scrollable
QWidget *dd = new QWidget(this);
dd->setGeometry(0,10,width,140);
dd->setStyleSheet("background: blue;");

QVBoxLayout *layout = new QVBoxLayout();
dd->setLayout(layout);

for (int i = 0; i < fValues.size(); i++)
{
    MyButton *button = new MyButton(fValues[i],dd);
    layout->addWidget(button);
}

QScrollArea *scroll = new QScrollArea(this);
scroll->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
scroll->setWidget(dd);

Contrary to my expectations, this is what I am getting (attached image). What am I doing wrong, and how do I fix this?

回答1:

You messed up the stack of items. The idea of having scrollable area is like this:

  • on the bottom is parent widget (for example QDialog)
  • on top of this is scrollable area (QScrollArea) of fixed size
  • on top of this is a widget (QWidget) of some size, where usually only part of it is visible (it's supposed to be bigger than scrollarea)
  • on top of this is a layout
  • and the last: layout manages child items (couple of QPushButton here)

Try this code:

int
main( int _argc, char** _argv )
{
    QApplication app( _argc, _argv );

    QDialog * dlg = new QDialog();
    dlg->setGeometry( 100, 100, 260, 260);

    QScrollArea *scrollArea = new QScrollArea( dlg );
    scrollArea->setVerticalScrollBarPolicy( Qt::ScrollBarAlwaysOn );
    scrollArea->setWidgetResizable( true );
    scrollArea->setGeometry( 10, 10, 200, 200 );

    QWidget *widget = new QWidget();
    scrollArea->setWidget( widget );

    QVBoxLayout *layout = new QVBoxLayout();
    widget->setLayout( layout );

    for (int i = 0; i < 10; i++)
    {
        QPushButton *button = new QPushButton( QString( "%1" ).arg( i ) );
        layout->addWidget( button );
    }

    dlg->show();

    return app.exec();
}

Worth to mention about QScrollArea::setWidgetResizable, which adjusts the child widget size dynamically according to its content.

And the result looks like this: