0

I have a qt-application with QListView, a custom model and a class inherited from QStyledItemDelegate to show custom items. Unfortunately it takes to long (5 seconds) when I add approximately 6000 items. Do you have a hint/solution for my problem?

Below you see my implementation:

The Model:

class AddressItemData : public QObject {
    Q_OBJECT

public:
    AddressItemData (QObject * parent = 0) : QObject(parent) {}

    QString address;
    QString name;
    bool inserted;
};

class AddressModel : public QAbstractListModel
{
    Q_OBJECT
public:
    AddressModel (QObject *parent = 0);

    int rowCount(const QModelIndex &parent = QModelIndex()) const {
       return addressItems.count();
    }

    QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const {
       if (!index.isValid())
           return QVariant();

       if (index.row() >= addressItems.size() || index.row() < 0)
           return QVariant();

       if (Qt::DisplayRole == role) {
           return QVariant::fromValue<AddressItemData*>(addressItems.at(index.row()));
       }

       return QVariant();
   }

    void addAddressItem(AddressItemData* addressItem){
       beginInsertRows(QModelIndex(), rowCount(), rowCount());
       addressItems.append(addressItem);
       endInsertRows();
    }

    void addAddressItems(QList<AddressItemData*> addressItems){
       beginInsertRows(QModelIndex(), rowCount(), rowCount() + addressItems.size() - 1);
       this->addressItems.append(addressItems);
       endInsertRows();
    }

    void removeAddressItem(AddressItemData* addressItem);

    void deleteAllAddressItems(void){
       beginRemoveRows(QModelIndex(), rowCount(), rowCount());
       for (int i = 0; i < addressItems.size(); ++i) {
           delete addressItems.at(i);
       }
       addressItems.clear();
       endRemoveRows();
    }


private:
    QList<AddressItemData*> addressItems;

};

For the model I created a custom add and delete method, which will be called from the delegate.

The ItemViewDelegate:

class AddressViewDelegate : public QStyledItemDelegate
{
    Q_OBJECT
public:
    AddressViewDelegate (QWidget *parent = 0) : QStyledItemDelegate(parent) {}

    void paint(QPainter *painter, const QStyleOptionViewItem &option,
                const QModelIndex &index) const {

        if(!index.isValid())
             return;

        painter->save();

        QStyleOptionViewItemV4 opt = option;

        if (option.state & QStyle::State_Selected)
             painter->fillRect(option.rect, option.palette.highlight());

        QRect addressRect = opt.rect;

        AddressItemData* d = index.data().value<AddressItemData*>();

        painter->setPen(Qt::black);
        painter->drawText(QRect(addressRect.left(), addressRect.top(),  addressRect.width(), addressRect.height()/2),
                       opt.displayAlignment,  d->address);
   }

    QSize sizeHint(const QStyleOptionViewItem &option,
                    const QModelIndex &index) const {
        if(!index.isValid())
             return QSize();

        QSize result = QStyledItemDelegate::sizeHint(option, index);
        result.setHeight(result.height()*2);

        return result;
   }
};

For test purposes, the application displays only the address. I want to show also the other information next to address in one line. Later I also want to add signal/slot-behavior for each row, but that's still a long way off.

The main:

AddressModel* model = new AddressModel;
AddressViewDelegate* viewDelegate = new AddressViewDelegate;
ui->listView->setItemDelegate(viewDelegate);
ui->listView->setModel(model);
ui->listView->setUniformItemSizes(true);
ui->listView->setLayoutMode(QListView::Batched);

QList<AddressItemData *> addressItems;
... for loop to add AddressItemData:
    AddressItemData* data = new AddressItemData;
    data->address = anotherTable.at(index);
    addressItems.append(data);
// ...

model->addAddressItems(addressItems);

In the main, I call addAddressItems but also with the single-call-variant it is slow. I hope my code is clear enough and I can help others as well.

Do you have an idea, why the adding-procedure is so slow?

Azeem
  • 11,148
  • 4
  • 27
  • 40
Mosa
  • 373
  • 1
  • 14
  • I'm not able to reproduce this. On my PC, `addAddressItems` call with 6000 items takes <1ms. On a general note - do not use QList, use std::vector. Btw your code doesn't compile, this line makes no sense `QVariant::fromValue(...)`. – Jaa-c Jan 18 '18 at 22:45
  • @Jaa-c oh sorry I corrected this line. I mean AddressItemModel*. I reduced my code here thats why there was this mistake. Can you reproduce it now? – Mosa Jan 19 '18 at 06:55
  • I don't think there is a general advantage of QVector over QList. Especially not if you spend a lot of time modifying the list. (I have no benchmarks however.) That said, none of those should be the cause of your problem. Try profiling it or measure some times to see which part exactly takes too long. The code looks like it should be fast enough to me. – SteakOverflow Jan 19 '18 at 07:33
  • @jaa I'm curious how you tested his code when it didn't compile? – Johannes Schaub - litb Jan 19 '18 at 09:25
  • @JohannesSchaub-litb I reduced the code for better readableness. For example I post only the .h-files and copied the .cpp-content into he .h-files. Some copy-paste-error – Mosa Jan 19 '18 at 09:30
  • @JohannesSchaub-litb: I fixed it, I only wanted to point that out.. – Jaa-c Jan 19 '18 at 09:51

0 Answers0