0
votes

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.

3

3 Answers

3
votes

I've found a workaround, just connect your listWidget's scroll bar's valueChanged(int) signal to the listWidget's updateEditorGeometries() slot:

connect(_listWidget->verticalScrollBar(),
        SIGNAL(valueChanged(int)),_listWidget,
        SLOT(updateEditorGeometries()));
connect(_listWidget->horizontalScrollBar(),
        SIGNAL(valueChanged(int)),_listWidget,
        SLOT(updateEditorGeometries()));
2
votes

As of 2013-08-05 git://gitorious.org/qt/qt.git revision 78b4162a352ddac398b8af7f8be33b009c333244 has the fix. Building from that revision or later fixes the issue.

This is the commit message for that revision:

Fix QListWidget item widget scroll bug

This fix applies the patch uploaded in the bug report. The patch was
provided by Qt-Commercial support but seems to have never found it's
way to the sources although the bug was fixed in Qt 5.

If you use homebrew you can simply:

brew install qt --build-from-source --HEAD

I have tested and confirmed this fixes the issue.

1
votes

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();