PDA

View Full Version : Flickering in QListView when appending items if VerticalScrollBarPolicy == AlwaysOff



bepaald
21st January 2019, 13:03
Hi!

I have a QListView whose model is getting items appended from a worker thread (as discussed here: https://forum.qt.io/topic/98481/ui-responsiveness-and-qlistview-updating-during-load-of-large-data-into-model). After implementing this in my actual program I noticed the listview flickering a lot while items were being added. After some testing I found that removing the call to QListView::setVerticalScrollBarPolicy(Qt::ScrollBa rAlwaysOff) removed all the flickering. I have made a little video showing this. I do not have the privileges to upload it here directly, but I've posted it here: https://gfycat.com/LivelyAptCassowary. At the start of the video, everything is fine with the scrollbar present, then without the scrollbar the list is barely usable while items are added.

It looks to me like the QListView is doing a lot of extra (unnecessary) repaints when the scrollbar is not there. I almost think this might be a bug, but maybe I'm just being stupid or missing something obvious. Does anyone know what's going on?

Also, is there a workaround? Any classes or functions to reimplement?

The code I used:


//main.cc
#include <QtWidgets>

#include "myitemmodel.h"

int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QWidget widget;

QVBoxLayout *layout = new QVBoxLayout(&widget);
QListView *listview = new QListView(&widget);
QPushButton *button = new QPushButton("Populate list", &widget);

MyItemModel *model = new MyItemModel;

listview->setModel(model);
listview->setMouseTracking(true);
listview->setEditTriggers(QListView::NoEditTriggers);
listview->setResizeMode(QListView::Adjust);
listview->setWordWrap(true);
listview->setVerticalScrollMode(QAbstractItemView::ScrollPer Pixel);
listview->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOf f);

listview->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff) ; // <-- PROBLEM!

QObject::connect(button, &QPushButton::clicked, model, &MyItemModel::loadData);

layout->addWidget(listview);
layout->addWidget(button);

widget.setMinimumSize(QSize(320, 380));

widget.show();
return app.exec();
}



//myitemmodel.h
#ifndef MYITEMMODEL_H_
#define MYITEMMODEL_H_

#include <QtWidgets>

class MyItemModel : public QStandardItemModel
{
Q_OBJECT;

bool d_cancel;
QThread *d_worker;

public:
inline MyItemModel(QWidget *parent = nullptr);
public slots:
inline void loadData();
inline void addAvailableItem(QStandardItem *item);
signals:
void itemAvailable(QStandardItem *item);
private:
inline void loadDataWorker();
};

inline MyItemModel::MyItemModel(QWidget *parent)
:
QStandardItemModel(parent),
d_cancel(false),
d_worker(nullptr)
{
connect(this, &MyItemModel::itemAvailable, this, &MyItemModel::addAvailableItem, Qt::QueuedConnection);
}

inline void MyItemModel::loadData()
{
// here, I should cancel any running threads and wait for them to stop
d_cancel = true;
if (d_worker)
{
d_worker->wait();
delete d_worker;
d_worker = nullptr;
}
d_cancel = false;

// clear the model
clear();

// start thread to load data
d_worker = QThread::create([=]{loadDataWorker();});
d_worker->start();
}

inline void MyItemModel::loadDataWorker()
{
for (uint i = 0; i < 2000; ++i)
{
if (d_cancel)
break;

QStandardItem *item = new QStandardItem;
item->setData("This is item " + QString::number(i), Qt::DisplayRole);
QThread::msleep(2);

emit itemAvailable(item);
}
}

inline void MyItemModel::addAvailableItem(QStandardItem *item)
{
appendRow(item);
}

#endif


Should compile with qmake -project QT+=widgets && qmake && make.

Thanks!

bepaald
29th January 2019, 16:39
I tried to work around this issue by hiding the scrollbar by setting its width to zero. Unfortunately using QListView::verticalScrollBar()->setStyleSheet("QScrollBar {width:0px;}"); produces the exact same flickering as calling QListView::setVerticalScrollBarPolicy(Qt::ScrollBa rAlwaysOff), while setting to 1px works flawlessly (with a weirdly slim scrollbar).

Any workaround suggestion is still highly appreciated.