Kot Shrodingera
Kot Shrodingera

Reputation: 105

How can I set maximum width to which QScrollArea (within QDialog) will expand without adding scrollbar?

I have QDialog and QScrollArea inside. When content in QScrollArea is small, dialog window is also small. When content width is increasing, dialog window's width is also encreasing but only to some fixed value.

When QPushButton's width in my example is about 450 or more, vertical scrollbar appears. How can I avoid this and let dialog window expand more?

class Dialog : public QDialog {
  Q_OBJECT
public:
  Dialog(QWidget *parent = nullptr) : QDialog(parent) {
    auto dialogLayout = new QVBoxLayout(this);

    auto scrollArea = new QScrollArea(this);
    scrollArea->setWidgetResizable(true);
    auto scrollWidget = new QWidget(scrollArea);
    auto scrollLayout = new QVBoxLayout(scrollWidget);
    scrollLayout->setAlignment(Qt::AlignTop);
    scrollArea->setWidget(scrollWidget);

    dialogLayout->addWidget(scrollArea);

    auto button = new QPushButton("Button", this);
    button->setFixedSize(500, 30);

    scrollLayout->addWidget(button);
  }
};

class MainWindow : public QMainWindow
{
  Q_OBJECT

public:
  MainWindow(QWidget *parent = nullptr) : QMainWindow(parent)
  {
    auto centralWidget = new QWidget(this);
    setCentralWidget(centralWidget);
    auto mainLayout = new QVBoxLayout(centralWidget);

    auto button = new QPushButton("Dialog", this);
    mainLayout->addWidget(button);

    connect(button, &QPushButton::clicked, this, []() {Dialog().exec();});
  }
};

I tried QDialog::setMaximumWidth, and setting Expanding size policy for both QDialog and QScrollArea but nothing helps

Upvotes: 0

Views: 1548

Answers (1)

Maxim Paperno
Maxim Paperno

Reputation: 4869

QScrollArea constrains the maximum size of its sizeHint() method (comes out to 468px on my current Win7 machine). You can see that here. (I didn't know this until now either... not sure why they chose to do it this way.)

So looks like you'll have to re-implement QScrollArea or find a different display strategy. To re-implement we just basically need to re-write the sizeHint() function but w/out the silly constraint.

#include <QApplication>
#include <QtWidgets>

class ScrollArea : public QScrollArea
{
  public:
    ScrollArea(QWidget *parent = nullptr) : QScrollArea(parent) {}

    QSize sizeHint() const
    {
      QSize sz = QScrollArea::viewportSizeHint();
      const int f = frameWidth() * 2;
      sz += QSize(f, f);
      if (verticalScrollBarPolicy() == Qt::ScrollBarAlwaysOn)
        sz.setWidth(sz.width() + verticalScrollBar()->sizeHint().width());
      if (horizontalScrollBarPolicy() == Qt::ScrollBarAlwaysOn)
        sz.setHeight(sz.height() + horizontalScrollBar()->sizeHint().height());
      return sz;
    }
};

class Dialog : public QDialog {
  public:
    Dialog(QWidget *parent = nullptr) : QDialog(parent) {
      auto dialogLayout = new QVBoxLayout(this);
      auto scrollArea = new ScrollArea(this);
      //scrollArea->setWidgetResizable(true);
      auto scrollWidget = new QWidget(this);
      auto scrollLayout = new QVBoxLayout(scrollWidget);
      auto button = new QPushButton("Button", this);
      button->setFixedSize(600, 30);

      scrollLayout->addWidget(button);
      scrollArea->setWidget(scrollWidget);
      dialogLayout->addWidget(scrollArea);
    }
};

int main(int argc, char *argv[])
{
  QApplication a(argc, argv);
  return Dialog().exec();
}

As a small aside, if you add the items to the scroll area in the order I show here, you do not technically need the setWidgetResizable(true) bit which I commented out (I noticed that in the original order you had it in, the inner widget wasn't being shown properly sized).

ADDED: The reason sizeHint() matters is because that's what QDialog uses to determine it's initial size. One could also (for example) re-implement QDialog::showEvent() and set a specific size for the dialog there based on whatever criteria make sense.

Upvotes: 1

Related Questions