Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Expanding multiple ListViews within QScrollArea.
Forum Updated to NodeBB v4.3 + New Features

Expanding multiple ListViews within QScrollArea.

Scheduled Pinned Locked Moved Solved General and Desktop
9 Posts 3 Posters 465 Views 3 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • M Offline
    M Offline
    MarkLT1
    wrote on last edited by
    #1

    I am trying to show several vertically stacked lists within a single QScrollArea. I would like the lists to expand so that they show all of their items (and don't have their own individual scrollbars), and have the QScrollArea scrollbar scroll the entire set.

    I've been trying the following:

    auto listsContainer = new QScrollArea(this);
    auto lcLayout = new QVBoxLayout();
    for (auto& qa : _qaLists) {
    	// Header for the list
    	auto l = new QLabel();
    	l->setText(qa.header.c_str());
    	l->setStyleSheet("QLabel { font-size: 18px }");
    	lcLayout->addWidget(l);
    	qa.listView->setModel(qa.model);
    	qa.listView->setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContents);
    	lcLayout->addWidget(qa.listView);
    }
    listsContainer->setLayout(lcLayout);
    

    However this gives lists that have their header, but then the list itself only shows a couple of items, and has its own scroll bar. Is there any way to tell the lists to expand so that they show all items (which would push lists/headers off the bottom of the container, and would then be scrolled vertically with the QScrollArea scrollbar). See the attached picture for what I'm seeing, vs. how I want it to work.

    79e698ea-f6a7-48d3-948a-0dd2a3ae1a94-image.png

    1 Reply Last reply
    0
    • SGaistS Offline
      SGaistS Offline
      SGaist
      Lifetime Qt Champion
      wrote on last edited by SGaist
      #2

      Hi and welcome to devnet,

      One thing you could do is subclcass QListView, reimplement sizeHint and use contentsRect + contentMargins to return the adequate size.

      Interested in AI ? www.idiap.ch
      Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

      1 Reply Last reply
      1
      • M Offline
        M Offline
        MarkLT1
        wrote on last edited by
        #3

        Thank you for the warm welcome!

        I will give that a try (I am pretty new to QT). To clarify- are "contentSize" and "contentMargins" automatically calculated? Or would I need to iterate over the items and calculate those myself?

        Pl45m4P 1 Reply Last reply
        0
        • M MarkLT1

          Thank you for the warm welcome!

          I will give that a try (I am pretty new to QT). To clarify- are "contentSize" and "contentMargins" automatically calculated? Or would I need to iterate over the items and calculate those myself?

          Pl45m4P Offline
          Pl45m4P Offline
          Pl45m4
          wrote on last edited by
          #4

          @MarkLT1 said in Expanding multiple ListViews within QScrollArea.:

          Or would I need to iterate over the items and calculate those myself?

          Hi, I think your solution is right here


          If debugging is the process of removing software bugs, then programming must be the process of putting them in.

          ~E. W. Dijkstra

          M 1 Reply Last reply
          1
          • SGaistS Offline
            SGaistS Offline
            SGaist
            Lifetime Qt Champion
            wrote on last edited by
            #5

            Sorry, there was a typo and the links were missing. Both are functions from QWidget.

            @Pl45m4's suggestion is good however it assumes that all items have the same height. Depending on what you put it there it might not be true.

            Interested in AI ? www.idiap.ch
            Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

            1 Reply Last reply
            0
            • Pl45m4P Pl45m4

              @MarkLT1 said in Expanding multiple ListViews within QScrollArea.:

              Or would I need to iterate over the items and calculate those myself?

              Hi, I think your solution is right here

              M Offline
              M Offline
              MarkLT1
              wrote on last edited by
              #6

              @Pl45m4 said in Expanding multiple ListViews within QScrollArea.:

              @MarkLT1 said in Expanding multiple ListViews within QScrollArea.:

              Or would I need to iterate over the items and calculate those myself?

              Hi, I think your solution is right here

              Thank you for this. I gave this a try in my derived ListView sizeHint() function:

              QSize MyListViewt::sizeHint() const
              {
              	int rows = model()->rowCount();
              	if (rows == 0)
              		return QSize(width(), 0);
              	int height = rows * sizeHintForRow(0);
              	return QSize(width(), height);
              }
              

              And when I set a breakpoint, I see that my new sizeHint() is being called and the height is being set to a reasonable number (for a large list, it is 3000+px). However, the rendered lists are still the same height they were before, with scrollbars. Its like the Layout is squashing everything down to fit in the box provided by the parent ScrollArea dimensions

              @SGaist-

              For your solution, when sizeHint() is called, contentsRect() returns a tiny box (24px wide by 98px tall), and the ListView ends up being extremely small. I am guessing I'm missing some vital step here.

              1 Reply Last reply
              0
              • SGaistS Offline
                SGaistS Offline
                SGaist
                Lifetime Qt Champion
                wrote on last edited by SGaist
                #7

                Here you have a variant in python that works quite well:

                from PySide6 import QtWidgets
                from PySide6 import QtCore
                
                app = QtWidgets.QApplication([])
                
                widget = QtWidgets.QWidget()
                layout = QtWidgets.QVBoxLayout(widget)
                for i in range(0, 3):
                    list_widget = QtWidgets.QListWidget()
                    list_widget.addItems([f"Test {item}" for item in range(0, 13)])
                    list_widget.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
                    list_widget.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
                    list_widget.setFixedSize(list_widget.sizeHintForColumn(0) + 2 * list_widget.frameWidth(),
                                             list_widget.sizeHintForRow(0) * list_widget.count() + 2 * list_widget.frameWidth())
                    layout.addWidget(list_widget)
                
                scroll_area = QtWidgets.QScrollArea()
                scroll_area.setWidget(widget)
                scroll_area.show()
                
                app.exec()
                

                Interested in AI ? www.idiap.ch
                Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                M 1 Reply Last reply
                0
                • M Offline
                  M Offline
                  MarkLT1
                  wrote on last edited by MarkLT1
                  #8

                  Ok, I think I got it working.

                  The first issue was with:

                  listsContainer->setLayout(lcLayout);
                  

                  Rather than adding a layout, I created a container widget, added the layout to that widget, and did setWidget() on the scrollarea.

                  Regarding the sizeHint, contentsRect doesn't seem to return the correct value, and all of the rows will be the same size, so I think it should probably work well. I did need to add the margin values to get rid of the scroll bar. So my working code looks like:

                  // Size hint code for MyListView
                  QSize MyListView::sizeHint() const
                  {
                  	QMargins margins = contentsMargins();
                  	int rows = model()->rowCount();
                  	if (rows == 0)
                  		return QSize(width(), 0);
                  	int height = rows * sizeHintForRow(0);
                  	return QSize(width(), height + margins.top() + margins.bottom());
                  }
                  

                  And the widget setup code:

                  	auto listsContainer = new QScrollArea(this);
                  	listsContainer->setWidgetResizable(true);
                  	auto listsWidget = new QWidget();
                  	auto lcLayout = new QVBoxLayout();
                  	for (auto& qa : _qaLists) {
                  		auto l = new QLabel();
                  		l->setText(qa.header.c_str());
                  		l->setStyleSheet("QLabel { font-size: 18px }");
                  		lcLayout->addWidget(l);
                  		// qa.listView is a MyListView object
                  		qa.listView->setModel(qa.model);
                  		qa.listView->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
                  		lcLayout->addWidget(qa.listView);
                  	}
                  	listsWidget->setLayout(lcLayout);
                  	listsContainer->setWidget(listsWidget);
                  
                  1 Reply Last reply
                  0
                  • SGaistS SGaist

                    Here you have a variant in python that works quite well:

                    from PySide6 import QtWidgets
                    from PySide6 import QtCore
                    
                    app = QtWidgets.QApplication([])
                    
                    widget = QtWidgets.QWidget()
                    layout = QtWidgets.QVBoxLayout(widget)
                    for i in range(0, 3):
                        list_widget = QtWidgets.QListWidget()
                        list_widget.addItems([f"Test {item}" for item in range(0, 13)])
                        list_widget.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
                        list_widget.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
                        list_widget.setFixedSize(list_widget.sizeHintForColumn(0) + 2 * list_widget.frameWidth(),
                                                 list_widget.sizeHintForRow(0) * list_widget.count() + 2 * list_widget.frameWidth())
                        layout.addWidget(list_widget)
                    
                    scroll_area = QtWidgets.QScrollArea()
                    scroll_area.setWidget(widget)
                    scroll_area.show()
                    
                    app.exec()
                    
                    M Offline
                    M Offline
                    MarkLT1
                    wrote on last edited by
                    #9

                    @SGaist said in Expanding multiple ListViews within QScrollArea.:

                    Here you have a variant in python that works quite well:

                    Thank you for this. I'll dig into what you're doing with sizeHints, and see if I can adapt it to my working code above. Would be nice to not be dependent on all list items being the same size.

                    1 Reply Last reply
                    0
                    • M MarkLT1 has marked this topic as solved on

                    • Login

                    • Login or register to search.
                    • First post
                      Last post
                    0
                    • Categories
                    • Recent
                    • Tags
                    • Popular
                    • Users
                    • Groups
                    • Search
                    • Get Qt Extensions
                    • Unsolved