Resizing QScrollArea issue
-
Dear all,
I have to create a scroll area with only the vertical scrolling bar, so I need the width fits exactly the content.
I have created this example with QtCreator:To fit the QScrollArea to the content, I add this code:
ui.scrollArea->setFixedWidth(ui.scrollAreaWidgetContents->minimumSizeHint().width());
But this does not produce the wanted result:
I have noticed that the problem in this example can be solved setting the QWidget of the scroll area as horizontal layout and removing the nested horizontal layout. The problem is that in my project I will have many widgets inside the scroll area, so I can't avoid to set it as vertical layout and to put inside many horizontal layouts and/or tabs.
How should I solve this problem?
-
@Mattia Hi, I think I kind of find a solution.
- (in cpp) Remove that setFixedWidth code.
- (in ui) Set horizontal size policy of scrollArea to "Fixed" as I mentioned.
- (in ui) Reset minimumSize of centralWidget to default (0 x 0)
- (in ui) Promote scrollArea to new class: ModScrollArea
modscrollarea.h
#ifndef MODSCROLLAREA_H #define MODSCROLLAREA_H #include <QScrollArea> class ModScrollArea : public QScrollArea { Q_OBJECT public: explicit ModScrollArea(QWidget *parent = nullptr); QSize sizeHint() const; protected: bool event(QEvent *e); private: mutable QSize widgetSize; }; #endif // MODSCROLLAREA_H
modscrollarea.cpp
#include "modscrollarea.h" #include <QEvent> #include <QScrollBar> ModScrollArea::ModScrollArea(QWidget *parent) : QScrollArea(parent) { } QSize ModScrollArea::sizeHint() const { int f = 2 * frameWidth(); QSize sz(f, f); int h = fontMetrics().height(); if (widget()) { if(!widgetSize.isValid()) widgetSize = widgetResizable() ? widget()->sizeHint() : widget()->size(); sz += widgetSize; } else { sz += QSize(12 * h, 8 * h); } if (verticalScrollBarPolicy() == Qt::ScrollBarAlwaysOn) sz.setWidth(sz.width() + verticalScrollBar()->sizeHint().width()); if (horizontalScrollBarPolicy() == Qt::ScrollBarAlwaysOn) sz.setHeight(sz.height() + horizontalScrollBar()->sizeHint().height()); return sz.boundedTo(QSize(sz.width(), 24 * h)); } bool ModScrollArea::event(QEvent *e) { if(e->type() == QEvent::LayoutRequest && widget()) { QSize newSize = widgetResizable() ? widget()->sizeHint() : widget()->size(); if(widgetSize != newSize) { widgetSize = newSize; updateGeometry(); } } return QScrollArea::event(e); }
You can have a try.
-
I don't quit understand your need.
But if you want scrollArea to fit its content width, you can set its horizontal sizePolicy to QSizePolicy::Fixed, this can be done in the designer.
Please note that the size hint of QLineEdit doesn't grow with its content text.
So if you want to show all the text in QLineEdit, you may need to set its minimum width. -
I need to programmatically resize the width of the QScrollArea according the width of its content. I can't fix the width before because the content can change.
ui.scrollArea->setFixedWidth(ui.scrollAreaWidgetContents->minimumSizeHint().width());
This should work, but like I said if I nest the content inside a vertical layout, this command does not do its job anymore...
-
-
@Mattia , @Bonnie
I'm following this one, because I'm also learning aboutQScrollArea
behaviour. I'd just like to throw in a quote from https://doc.qt.io/qt-5/qscrollarea.html#widgetResizable-propRegardless of this property, you can programmatically resize the widget using widget()->resize(), and the scroll area will automatically adjust itself to the new size.
Which implies we shouldn't need to be doing stuff ourselves on the
QScrollArea
to make it fit when the content resizes??EDIT And I see now from your file below that you are setting
widgetResizable
totrue
, which means you are resizing the widget to fit the scrollarea, when maybe you want the scrollarea to resize to fit the widget instead?? -
@Bonnie Sure!
main.cpp
#include "QtGuiApplication1.h" #include <QtWidgets/QApplication> #include <Windows.h> int main(int argc, char *argv[]) { QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QApplication a(argc, argv); QtGuiApplication1 w; w.show(); return a.exec(); }
QtGuiApplication1.h
#pragma once #include <QtWidgets/QMainWindow> #include "ui_QtGuiApplication1.h" class QtGuiApplication1 : public QMainWindow { Q_OBJECT public: QtGuiApplication1(QWidget *parent = Q_NULLPTR); private: Ui::QtGuiApplication1Class ui; };
QtGuiApplication1.cpp
#include "QtGuiApplication1.h" QtGuiApplication1::QtGuiApplication1(QWidget *parent) : QMainWindow(parent) { QString text; ui.setupUi(this); ui.scrollArea->setFixedWidth(ui.scrollAreaWidgetContents->minimumSizeHint().width()); }
QtGuiApplication1.ui
<?xml version="1.0" encoding="UTF-8"?> <ui version="4.0"> <class>QtGuiApplication1Class</class> <widget class="QMainWindow" name="QtGuiApplication1Class"> <property name="geometry"> <rect> <x>0</x> <y>0</y> <width>411</width> <height>289</height> </rect> </property> <property name="windowTitle"> <string>QtGuiApplication1</string> </property> <widget class="QWidget" name="centralWidget"> <property name="minimumSize"> <size> <width>225</width> <height>0</height> </size> </property> <layout class="QHBoxLayout" name="horizontalLayout"> <item> <widget class="QScrollArea" name="scrollArea"> <property name="sizePolicy"> <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> <property name="horizontalScrollBarPolicy"> <enum>Qt::ScrollBarAsNeeded</enum> </property> <property name="widgetResizable"> <bool>true</bool> </property> <widget class="QWidget" name="scrollAreaWidgetContents"> <property name="geometry"> <rect> <x>0</x> <y>0</y> <width>338</width> <height>214</height> </rect> </property> <property name="sizePolicy"> <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> <layout class="QVBoxLayout" name="verticalLayout"> <item> <layout class="QHBoxLayout" name="horizontalLayout_2"> <item> <widget class="QLabel" name="label_2"> <property name="text"> <string>LongSizeTextLabel</string> </property> </widget> </item> <item> <widget class="QLineEdit" name="lineEdit"> <property name="sizePolicy"> <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> <property name="text"> <string/> </property> </widget> </item> <item> <widget class="QPushButton" name="pushButton"> <property name="text"> <string>PushButton</string> </property> </widget> </item> </layout> </item> </layout> </widget> </widget> </item> <item> <widget class="QLabel" name="label"> <property name="text"> <string>TextLabel</string> </property> </widget> </item> </layout> </widget> <widget class="QMenuBar" name="menuBar"> <property name="geometry"> <rect> <x>0</x> <y>0</y> <width>411</width> <height>22</height> </rect> </property> </widget> <widget class="QToolBar" name="mainToolBar"> <attribute name="toolBarArea"> <enum>TopToolBarArea</enum> </attribute> <attribute name="toolBarBreak"> <bool>false</bool> </attribute> </widget> <widget class="QStatusBar" name="statusBar"/> </widget> <layoutdefault spacing="6" margin="11"/> <resources> <include location="QtGuiApplication1.qrc"/> </resources> <connections/> </ui>
-
@Mattia Hi, I think I kind of find a solution.
- (in cpp) Remove that setFixedWidth code.
- (in ui) Set horizontal size policy of scrollArea to "Fixed" as I mentioned.
- (in ui) Reset minimumSize of centralWidget to default (0 x 0)
- (in ui) Promote scrollArea to new class: ModScrollArea
modscrollarea.h
#ifndef MODSCROLLAREA_H #define MODSCROLLAREA_H #include <QScrollArea> class ModScrollArea : public QScrollArea { Q_OBJECT public: explicit ModScrollArea(QWidget *parent = nullptr); QSize sizeHint() const; protected: bool event(QEvent *e); private: mutable QSize widgetSize; }; #endif // MODSCROLLAREA_H
modscrollarea.cpp
#include "modscrollarea.h" #include <QEvent> #include <QScrollBar> ModScrollArea::ModScrollArea(QWidget *parent) : QScrollArea(parent) { } QSize ModScrollArea::sizeHint() const { int f = 2 * frameWidth(); QSize sz(f, f); int h = fontMetrics().height(); if (widget()) { if(!widgetSize.isValid()) widgetSize = widgetResizable() ? widget()->sizeHint() : widget()->size(); sz += widgetSize; } else { sz += QSize(12 * h, 8 * h); } if (verticalScrollBarPolicy() == Qt::ScrollBarAlwaysOn) sz.setWidth(sz.width() + verticalScrollBar()->sizeHint().width()); if (horizontalScrollBarPolicy() == Qt::ScrollBarAlwaysOn) sz.setHeight(sz.height() + horizontalScrollBar()->sizeHint().height()); return sz.boundedTo(QSize(sz.width(), 24 * h)); } bool ModScrollArea::event(QEvent *e) { if(e->type() == QEvent::LayoutRequest && widget()) { QSize newSize = widgetResizable() ? widget()->sizeHint() : widget()->size(); if(widgetSize != newSize) { widgetSize = newSize; updateGeometry(); } } return QScrollArea::event(e); }
You can have a try.