Results 1 to 4 of 4

Thread: How to update size of nested QWidget?

  1. #1
    Join Date
    Aug 2020
    Posts
    19
    Thanks
    3
    Qt products
    Qt5
    Platforms
    Windows

    Default How to update size of nested QWidget?

    I'm using Qt 5.15 with C++17. I have a hierarchy of Widgets like hinted in the title:
    Qt Code:
    1. MainWindow : QMainWindow
    2. ->centralWidget() = QScrollArea
    3. ->widget() = QWidget
    4. ->layout() = QVBoxLayout
    5. ->children() = [
    6. InnerWidget,
    7. InnerWidget,
    8. InnerWidget,
    9. ...
    10. ]
    To copy to clipboard, switch view to plain text mode 
    with
    Qt Code:
    1. InnerWidget.children() = [ QLabel, QLabel ]
    To copy to clipboard, switch view to plain text mode 
    .
    I have set
    Qt Code:
    1. InnerWidget::setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum)
    To copy to clipboard, switch view to plain text mode 
    inside InnerWidget's constructor.

    The QLabels inside InnerWidget are initialized with some QPixmap like
    Qt Code:
    1. label->setPixmap(img);
    2. label->setFixedSize(img.size());
    To copy to clipboard, switch view to plain text mode 
    _________________


    This all works fine, however now I added an option to zoom all the pixmaps to the MainWindow's menubar. I connect to a signal MainWindow::zoom_inner(.., which itself calls InnerWidget::zoom(.. on every InnerWidget, which resizes the images / labels like this:
    Qt Code:
    1. auto scaled = img.scaled(img.size() * factor);
    2. label->setPixmap(scaled);
    3. label->setFixedSize(scaled.size());
    To copy to clipboard, switch view to plain text mode 

    Finally I update the size of the MainWindow by finding the maximum InnerWidget.frameGeometry().width() (= inner_max_width) and calling
    Qt Code:
    1. void MainWindow::zoom_inner() {
    2. // ...
    3. setMaximumWidth(inner_max_width + centralWidget()->verticalScrollBar()->width() + 1);
    4. resize(maximumWidth(), size().height());
    5. }
    To copy to clipboard, switch view to plain text mode 
    _________________

    Now after calling MainWindow::zoom(.., the window seems to resize to the correct size, as do the QLabel's inside the InnerWidget's. However, the InnerWidget's themselves do not resize at all, they just stay the same size as before and I have no idea why. I tried calling many combinations of
    Qt Code:
    1. adjustSize();
    2. update();
    3. layout()->update();
    4. updateGeometry();
    To copy to clipboard, switch view to plain text mode 
    on any of the MainWindow,QScrollArea,InnerWidget but nothing happens.. even calling
    Qt Code:
    1. InnerWidget::resize(new_size)
    To copy to clipboard, switch view to plain text mode 
    has no effect. Clearly InnerWidget::sizeHint() gives the correct value, because the MainWindow size after MainWindow::zoom(.. is correct. So why do the InnerWidget's refuse to resize to fit the QLabel's, even though sizePolicy is set to QSizePolicy::Minimum?

    This seems like some sort of misunderstanding on my part so I'm hoping the answer is simple and doesn't need a MWE. I've tried the docs but couldn't find a solution.

  2. #2
    Join Date
    Jan 2008
    Location
    Alameda, CA, USA
    Posts
    5,103
    Thanks
    289
    Thanked 844 Times in 831 Posts
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: How to update size of nested QWidget?

    sizePolicy is set to QSizePolicy::Minimum
    This is telling the VBox layout that the widget's sizes are fixed at their minimum sizes. You need a size policy that includes "Expanding" or use "Preferred".
    <=== The Great Pumpkin says ===>
    Please use CODE tags when posting source code so it is more readable. Click "Go Advanced" and then the "#" icon to insert the tags. Paste your code between them.

  3. #3
    Join Date
    Aug 2020
    Posts
    19
    Thanks
    3
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: How to update size of nested QWidget?

    I do want the InnerWidget's to be fixed at their minimum size, but the minimum size itself should update after resizing the QPixmap's.
    This doesn't seem to happen, even though InnerWidget::sizeHint clearly updates correctly, since the MainWindow is resized correctly.

    Seems I cannot edit my post, but I made a MWE:

    include/NestedWidgetResizeIssue_MWE.hh
    Qt Code:
    1. #include <vector>
    2.  
    3. #include <QtGui/QPixmap>
    4. #include <QtWidgets/QAction>
    5. #include <QtWidgets/QLabel>
    6. #include <QtWidgets/QMainWindow>
    7. #include <QtWidgets/QMenu>
    8. #include <QtWidgets/QScrollArea>
    9. #include <QtWidgets/QWidget>
    10. #include <QtWidgets/QFrame>
    11.  
    12. class InnerWidget : public QFrame {
    13.  
    14. QPixmap m_img_1;
    15. QPixmap m_img_2;
    16. QLabel* m_label_1;
    17. QLabel* m_label_2;
    18.  
    19. static QPixmap create_black_img();
    20. static void update_img_label(const QPixmap& img, QLabel* label);
    21. static void init_img_label(QPixmap& img, QLabel*& label);
    22. static void zoom_img_label(double factor, QPixmap& img, QLabel* label);
    23.  
    24. public:
    25. InnerWidget();
    26.  
    27. void zoom(double factor);
    28. };
    29.  
    30. // --------------------------------------------------
    31.  
    32. class MainWindow : public QMainWindow {
    33. Q_OBJECT
    34.  
    35. QMenu* m_edit_menu;
    36. QAction* m_zoom_action;
    37.  
    38. QScrollArea* m_central;
    39. QWidget* m_main;
    40.  
    41. std::vector<InnerWidget*> m_entries;
    42.  
    43. void update_max_width();
    44.  
    45. private slots:
    46. void zoom_inner();
    47.  
    48. public:
    49. MainWindow();
    50. };
    To copy to clipboard, switch view to plain text mode 

    src/NestedWidgetResizeIssue_MWE.cc
    Qt Code:
    1. #include <cmath>
    2.  
    3. #include <QtGui/QPainter>
    4. #include <QtWidgets/QMenuBar>
    5. #include <QtWidgets/QVBoxLayout>
    6. #include <QtWidgets/QHBoxLayout>
    7. #include <QtWidgets/QInputDialog>
    8. #include <QtWidgets/QScrollBar>
    9.  
    10. #include <NestedWidgetResizeIssue_MWE.hh>
    11.  
    12. InnerWidget::InnerWidget() {
    13. setFrameShape(QFrame::Panel);
    14. auto* layout = new QHBoxLayout{};
    15.  
    16. init_img_label(m_img_1, m_label_1);
    17. init_img_label(m_img_2, m_label_2);
    18. layout->addWidget(m_label_1);
    19. layout->addWidget(m_label_2);
    20.  
    21. setLayout(layout);
    22. setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
    23. adjustSize();
    24. }
    25.  
    26. QPixmap InnerWidget::create_black_img() {
    27. QPixmap img(400, 400);
    28. QPainter p(&img);
    29. img.fill(QColor::fromRgb(0, 0, 0));
    30. return img;
    31. }
    32.  
    33. void InnerWidget::update_img_label(const QPixmap& img, QLabel* label) {
    34. label->setPixmap(img);
    35. label->setFixedSize(img.size());
    36. }
    37.  
    38. void InnerWidget::init_img_label(QPixmap& img, QLabel*& label) {
    39. img = create_black_img();
    40. label = new QLabel{};
    41. update_img_label(img, label);
    42. }
    43.  
    44. void InnerWidget::zoom_img_label(double factor, QPixmap& img, QLabel* label) {
    45. img = img.scaled(img.size() * factor);
    46. update_img_label(img, label);
    47. }
    48.  
    49. void InnerWidget::zoom(double factor) {
    50. zoom_img_label(factor, m_img_1, m_label_1);
    51. zoom_img_label(factor, m_img_2, m_label_2);
    52. }
    53.  
    54. // --------------------------------------------------
    55.  
    56. MainWindow::MainWindow() :
    57. m_edit_menu{ menuBar()->addMenu("&Edit") },
    58. m_zoom_action{ new QAction{ "&Zoom" } },
    59. m_central{ new QScrollArea },
    60. m_main{ new QWidget } {
    61.  
    62. connect(m_zoom_action, &QAction::triggered, this, &MainWindow::zoom_inner);
    63. m_edit_menu->addAction(m_zoom_action);
    64.  
    65. auto* layout = new QVBoxLayout{};
    66. layout->setContentsMargins(0, 0, 0, 0);
    67.  
    68. for (int i = 0; i < 2; ++i) {
    69. auto* entry = new InnerWidget;
    70. m_entries.push_back(entry);
    71. layout->addWidget(entry);
    72. }
    73.  
    74. m_main->setLayout(layout);
    75. m_central->setWidget(m_main);
    76. setCentralWidget(m_central);
    77.  
    78. show();
    79. update_max_width();
    80. resize(maximumWidth(), 500);
    81. }
    82.  
    83. void MainWindow::zoom_inner() {
    84. bool confirm = false;
    85. auto factor = QInputDialog::getDouble(this, "Zoom images", "Factor", 1.0, 0.1, 2.0, 2, &confirm, Qt::WindowFlags{}, 0.05);
    86. if (!confirm) return;
    87.  
    88. for (auto* e : m_entries) {
    89. e->zoom(factor);
    90. e->adjustSize();
    91. }
    92.  
    93. update_max_width();
    94. resize(maximumWidth(), size().height());
    95. }
    96.  
    97. void MainWindow::update_max_width() {
    98. int max_entry_width = 0;
    99. for (const auto* e : m_entries)
    100. max_entry_width = std::max(max_entry_width, e->width());
    101.  
    102. setMaximumWidth(max_entry_width + m_central->verticalScrollBar()->width() + 3);
    103. }
    To copy to clipboard, switch view to plain text mode 

    src/main.cc
    Qt Code:
    1. #include <QtWidgets/QApplication>
    2.  
    3. #include <NestedWidgetResizeIssue_MWE.hh>
    4.  
    5. int main(int argc, char** argv) {
    6. QApplication app(argc, argv);
    7. MainWindow win;
    8. return app.exec();
    9. }
    To copy to clipboard, switch view to plain text mode 

    CMakeLists.txt
    Qt Code:
    1. cmake_minimum_required(VERSION 3.17)
    2. project(Test)
    3.  
    4. add_compile_options(-Wall -Wextra -pedantic)
    5. set(CMAKE_CXX_STANDARD 17)
    6.  
    7. set(CMAKE_AUTOMOC ON)
    8. set(CMAKE_AUTORCC ON)
    9. set(CMAKE_AUTOUIC ON)
    10. cmake_policy(SET CMP0100 NEW)
    11.  
    12. find_package(Qt5 COMPONENTS Widgets REQUIRED)
    13.  
    14. include_directories(include)
    15.  
    16. add_executable(Test
    17. src/main.cc
    18. include/NestedWidgetResizeIssue_MWE.hh
    19. src/NestedWidgetResizeIssue_MWE.cc
    20. )
    21.  
    22. target_link_libraries(Test
    23. Qt::Widgets
    24. )
    25.  
    26. install(TARGETS
    27. Test
    28. DESTINATION "${CMAKE_SOURCE_DIR}/bin")
    To copy to clipboard, switch view to plain text mode 

    build.sh
    Qt Code:
    1. #!/bin/bash
    2.  
    3. mkdir -p build bin
    4.  
    5. cd build
    6. cmake ..
    7. make
    8. make install
    To copy to clipboard, switch view to plain text mode 

    Again to clarify
    What I want to happen: all InnerWidget's should automatically resize (to a fixed size that is just enough to fully show the resized images) after confirming the zoom factor.
    Issue: Everything except the InnerWidget's resizes correctly. Even calling InnerWidget::resize(.. directly has no effect, why?

    EDIT

    It seems I need to make the QScrollArea's widget resizable:

    Qt Code:
    1. MainWindow::MainWindow()
    2. // ...
    3. {
    4.  
    5. // ...
    6. m_central->setWidget(m_main);
    7. m_central->setWidgetResizable(true); // I added this
    8. setCentralWidget(m_central);
    9. // ...
    10. }
    To copy to clipboard, switch view to plain text mode 

    This works, but I don't understand why it is needed .. according to the documentation:
    (...) Regardless of this property, you can programmatically resize the widget using widget()->resize(), and the scroll area will automatically adjust itself to the new size.
    But calling InnerWidget::resize(.. did nothing. What am I missing?
    Last edited by Maryu; 25th December 2021 at 14:20.

  4. #4
    Join Date
    Jan 2008
    Location
    Alameda, CA, USA
    Posts
    5,103
    Thanks
    289
    Thanked 844 Times in 831 Posts
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: How to update size of nested QWidget?

    But calling InnerWidget::resize(.. did nothing. What am I missing?
    If you have widgets inside of a layout, the layout is in charge of the sizes. That's why there are size policies, size hints, QSpacerItem, stretch factors, and so forth, to help guide the layout as it resizes its content.

    If your labels are growing too large with resizing, then adding a spacer at the bottom and/or top will squish them to their preferred sizes (QBoxLayout::addStretch()).
    <=== The Great Pumpkin says ===>
    Please use CODE tags when posting source code so it is more readable. Click "Go Advanced" and then the "#" icon to insert the tags. Paste your code between them.

Similar Threads

  1. QWidget::size() vs QWidget::geometry()
    By 33333 in forum Newbie
    Replies: 1
    Last Post: 13th June 2014, 07:06
  2. Replies: 1
    Last Post: 30th May 2014, 17:09
  3. QWidget update get so cpu usage
    By danics in forum Qt Programming
    Replies: 8
    Last Post: 20th August 2012, 08:07
  4. QWidget::update does not work!
    By sapali in forum Qt Programming
    Replies: 8
    Last Post: 17th March 2011, 16:56
  5. update() in QWidget
    By salmanmanekia in forum Qt Programming
    Replies: 5
    Last Post: 28th July 2008, 08:03

Tags for this Thread

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Digia, Qt and their respective logos are trademarks of Digia Plc in Finland and/or other countries worldwide.