Search code examples
macosqtscrollqlistwidget

QListWidget with custom widget does not scroll properly in Mac OS


In my application I'm having a QListWidget with custom widget items, containing among others a progress bar, set by QListWidget::setWidget(). I have been forced using a QListWidget instead of a QListView and a delegate, because the view/delegate solution does not animate the progress bar in the item widget as it would do normally.

My problem is that when scrolling the QListWidget, the custom widgets does not follow. They seem to be simply "glued" to the background. Only when resizing the surrounding widget manually, the QListWidget rearranges the child widgets correctly.

Here's how I'm adding a widget to the QListWidget:

QListWidgetItem* widgetItem = new QListWidgetItem("");
DownloadItemForm* dlItemForm = new DownloadItemForm(el);
widgetItem->setSizeHint(dlItemForm->size());
ui->listWidget->addItem(widgetItem);
ui->listWidget->setItemWidget(widgetItem, dlItemForm);
widgetItems.insert(el, widgetItem);

Am I missing something here? Seems like others are having problems as well (the last comment is mine):

https://bugreports.qt-project.org/browse/QTBUG-27043

Does anyone know of a workaround, or am I simply just missing something here?

Edit:

Just to clarify a bit further: I'm using Qt 4.8.4. While I hoped the issue would be fixed in 5.x, it's still there in 5.0.1 On Mac OS, a progress bar is animated: Even when there is no progress update, the progress bar has a slowly flowing animation within it. This animation is not running when using view based widget and an item delegate. Running the Torrent Qt example on a Mac will support this claim. The progress bar animation works when using QListWidget, injecting widget items containing a form widget with a progress bar.

Looking at the Qt 4.8.4 source, QListWidget::setItemWidget() looks like this:

void QListWidget::setItemWidget(QListWidgetItem *item, QWidget *widget)
{
    Q_D(QListWidget);
    QModelIndex index = d->listModel()->index(item);
    QAbstractItemView::setIndexWidget(index, widget);
}

which tells me that the problem probably lies within QAbstractItemView. I suppose I'll have to jump into it and try to fix the problem from there, and hopefully create a patch, unless someone comes up with a revelation.


Solution

  • I applied this patch provided to me by Qt Commercial Support. This resolved my Mac scroll problems on Qt 4.8.5:

    --- /Users/irfanomair/dev/qt-src-carbon-4.8.0/src/gui/kernel/qwidget_mac.mm 2011-12-15 10:38:21.000000000 -0800
    +++ kernel/qwidget_mac.mm   2012-09-18 17:17:03.000000000 -0700
    @@ -1,22 +1,41 @@
    
    @@ -4684,15 +4703,14 @@
         }
    
         // Scroll the whole widget if qscrollRect is not valid:
    -    QRect validScrollRect = qscrollRect.isValid() ? qscrollRect : q->rect();
    -    validScrollRect &= clipRect();
    +    QRect validScrollRect = qscrollRect.isValid() ? qscrollRect : QRect(0, 0, q->width(), q->height());
    
         // If q is overlapped by other widgets, we cannot just blit pixels since
         // this will move overlapping widgets as well. In case we just update:
         const bool overlapped = isOverlapped(validScrollRect.translated(data.crect.topLeft()));
         const bool accelerateScroll = accelEnv && isOpaque && !overlapped;
         const bool isAlien = (q->internalWinId() == 0);
    -    const QPoint scrollDelta(dx, dy);
    +
    
         // If qscrollRect is valid, we are _not_ supposed to scroll q's children (as documented).
         // But we do scroll children (and the whole of q) if qscrollRect is invalid. This case is
    @@ -4714,7 +4732,6 @@
             }else {
                 update_sys(qscrollRect);
             }
    -        return;
         }
    
     #ifdef QT_MAC_USE_COCOA
    @@ -4731,6 +4748,7 @@
         // moved when the parent is scrolled. All directly or indirectly moved
         // children will receive a move event before the function call returns.
         QWidgetList movedChildren;
    +    const QPoint scrollDelta(dx, dy);
         if (scrollChildren) {
             QObjectList children = q->children();