Как я могу установить максимальную ширину, до которой QScrollArea (в QDialog) будет расширяться без добавления полосы прокрутки?

#qt #qdialog #qscrollarea

#qt #qdialog #qscrollarea

Вопрос:

У меня есть QDialog и QScrollArea внутри. Когда содержимое в QScrollArea маленьком, диалоговое окно также мало. Когда ширина содержимого увеличивается, ширина диалогового окна также увеличивается, но только до некоторого фиксированного значения.

Когда QPushButton ширина в моем примере составляет около 450 или более, появляется вертикальная полоса прокрутки. Как я могу избежать этого и позволить диалоговому окну расширяться больше?

 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, amp;QPushButton::clicked, this, []() {Dialog().exec();});
  }
};
  

Я пробовал QDialog::setMaximumWidth и устанавливал политику расширения размера для обоих QDialog и QScrollArea , но ничего не помогает

Ответ №1:

QScrollArea ограничивает максимальный размер своего sizeHint() метода (получается 468 пикселей на моей текущей машине Win7). Вы можете увидеть это здесь. (Я тоже этого до сих пор не знал… не уверен, почему они решили сделать это таким образом.)

Похоже, вам придется повторно реализовать QScrollArea или найти другую стратегию отображения. Для повторной реализации нам просто нужно переписать sizeHint() функцию, но без глупого ограничения.

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

В качестве небольшого отступа, если вы добавите элементы в область прокрутки в порядке, который я показываю здесь, вам технически не понадобится setWidgetResizable(true) бит, который я прокомментировал (я заметил, что в исходном порядке, в котором он у вас был, внутренний виджет отображался с неправильным размером).

ДОБАВЛЕНО: Причина sizeHint() имеет значение, потому что это то, что QDialog используется для определения его начального размера. Можно также (например) повторно реализовать QDialog::showEvent() и установить определенный размер для диалогового окна там на основе любых критериев, имеющих смысл.

Комментарии:

1. Большое вам спасибо! О заполнении 2px: может быть, нам нужно добавить QSize(2 * frameWidth(), 2 * frameWidth()) в sz, как в начале оригинальной sizeHint() реализации? О setWidgetResizable() : это требуется, если в моем случае что-то будет добавлено к scrollLayout после scrollWidget установки

2. @Kot, добро пожаловать, и да, вы абсолютно правы, добавление frameWidth() * 2 работает без необходимости дополнительного заполнения. Я отредактировал код в своем ответе.

3. В вашем коде ошибка, которую я заметил только сейчас. в SizeHint вы проверяете наличие horizontalScrollBar , но добавляете verticalScrollBar высоту и наоборот