QScrollArea with list of custom widgets



  • Hello everyone,

    I'm having trouble building a scrollable list of custom widgets.
    After spending a few days trying I now know that I dont know enough about the Qt Layout system to make this work.

    To give a better understanding of what I am looking for, I created a small picture:

    My Sketch (Follow the Link if it is not displayed correctly)

    Okay. Everything in the picture is the contents of my QScrollArea.
    In the ScrollArea I created a QWidget for containing everything.
    The inner custom widgets are Chat-Bubbles, like in WhatsApp or other App-Style messengers. As they contain text and some additional information, it is not possible to give a definitive size-hint.

    Questions:

    • How can the described behavior be achieved? Everything I have found and/or tried said that I should set size hints, which does not really work with heightForWidth, at least in my case.
    • Do I have to create a custom Layout Manager for this?

    If there are any questions I will try to help.

    Thank you in advance!


  • Lifetime Qt Champion

    Hi,

    Since it's for a chat like thingy, did you consider using e.g. QListView with a custom QStyledItemDelegate ?



  • @SGaist I looked at it, but as far as I see, it is made for "equally-sized" items, which mine most certainly are not.
    Can I use QWidgets inside the Delegate for "painting" my items?



  • I have used a scroll area for something similar. I setup mine a little different. I use widgets to contain each child item (not layouts)

    // constructor of parent widget
    
    	scroll_area = new QScrollArea(this);
    	scroll_area->setWidgetResizable(true);
    	parent_widget_layout->addWidget(scroll_area);
    
    	d_scroll_area_widget = new QWidget();
    	scroll_area->setWidget(d_scroll_area_widget);
    	
    	d_scroll_area_layout = new QVBoxLayout(d_scroll_area_widget);
    	
    // see note below for explanation of spacer
    	d_bottom_vertical_spacer = new QSpacerItem(100, 20, QSizePolicy::Minimum, QSizePolicy::Expanding);
    	d_scroll_area_layout->addItem(d_bottom_vertical_spacer);
    

    Too add items

    	d_scroll_area_layout->removeItem(d_bottom_vertical_spacer);
    ...
    	d_scroll_area_layout->addWidget(new_widget_item);
    	d_scroll_area_layout->addItem(d_bottom_vertical_spacer);
    

    The bottom spacer is to make sure that if there is only one child widget of the scroll area it is not resized to fill all the available space. The bottom spacer is always moved to the bottom.

    Removing items is a bit more tougher. Actually, in my implementation, I don't. I hide the ones I want to remove and re-assign them if they are re-used in the future. In my case it works for what I need it to do but it may not be practical if you have something where you want to insert / delete / move items.

    As @SGaist mentioned you can use a QListView/QListWidget. The items do not need to be the same size and they can be resized after the fact if more or less information is displayed which changes the size.

    // Constructor
    	d_ReportListView = new TListView;  // subclass of QListWidget
    	d_ReportListView->setDragEnabled(true);
    	d_ReportListView->setDragDropMode(QAbstractItemView::InternalMove);
    	d_ReportListView->setSelectionMode(QAbstractItemView::ExtendedSelection);
    	d_ReportListView->setAutoScroll(true);
    	d_ReportListView->setAutoScrollMargin(48);
    	d_ReportListView->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
    	d_ReportListView->setUniformItemSizes(false);
    	d_ReportListView->setResizeMode(QListView::Adjust);
    
    // important function to enable resizing QListWidgetItems
    // if a list widget item size is changed update the size hits of that item
    void TListView::UpdateSizeHints(void)
    {
    	TListViewItem						*LVItem;
    	QSize								ItemSize;
    	int									LineHeight;
    
    	LineHeight = TListViewItem::LineHeight();  // fixed line height
    	ItemSize = this->size();  // size of parent
    
    	ItemSize.setHeight(num_lines * LineHeight);  // only adjusting height to fit required lines
    
    	// LVItem = pointer to current QListWidgetItem that need to be set or changed
    	LVItem->setSizeHint(ItemSize);
    }

Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.