Important: Please read the Qt Code of Conduct -

QListView scrolls up on list item drop.

  • Hi guys.

    I read a couple of notes about enabling items reordering in the QListView. I reimplemented flags() and supportedDropActions() methods and it seems to be working. I can take an item from the list and drop it in another position and it moves their correctly except the listview itself scrolls to the very top as soon as I drop the item and the wrong item get's selected. Why doesn't it remember where it was before the drop? What I can do to solve this? And also where I should specify which item must be selected?

    Thanks for any help!

  • Lifetime Qt Champion

    Hi and welcome to devnet,

    As for your problem, can you provide a minimal sample that reproduce the behavior ?

    Also, what version of Qt are you using ? On which OS ?

  • It's Qt 5.2.0 on Windows 7. I'm using Ct Creator.
    What i did is:
    1) Added a List View using the disigner
    2) Then I set it properties:
    dragEnabled - true
    dragDropOverWriteMode - false
    dragDropOverMode - InternalMove
    defaultDropAction - MoveAction
    Scroll Modes - perItem
    movement - free or snap;

    *3) *I created a new class named PlayListModel inherited from QStingListModel
    @class PlayListModel : public QStringListModel

    PlayListModel(QObject *parent) : QStringListModel(parent)

    Qt::ItemFlags flags(const QModelIndex &index) const;
    Qt::DropActions supportedDropActions() const    {        return Qt::CopyAction | Qt::MoveAction;    }
    int rowCount(const QModelIndex &parent) const;


    Qt::ItemFlags PlayListModel::flags(const QModelIndex &index) const
    if (index.isValid())
    return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled;
    return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled;

    int PlayListModel::rowCount(const QModelIndex &parent) const
    return 0;
    return stringList().length();

    *4) *In my mainwindow function I populate my model class with items
    @for(int i = 0; i < 25; i++)
    QModelIndex index = playListsModel->index(i);
    playListsModel->setData(index, "Item"+QString::number(i+1));

    and then assign it to List View's model.

    @ui->listsView->setModel(playListsModel); @

    Run the program and get such a behaviour.

  • Interesting. It happens only when the list widget or list view are created in the designer. If I create it in code and just
    then it works as I want it to... hmm.

    Where's the bug?
    Is it the compiler or ide problem?? Or just some parameter I missed somewhere in the designer or maybe the defaults in the designer differ from those in the framework itself?

    I still can't make it work via the designer.

  • Lifetime Qt Champion

    Sounds strange indeed

    Can you compare the values of these properties for both widgets ?

  • The same.... Actually I found out that it has nothing to do with the designer and only happens to QListView. I added both QListWidget and QListView to the layout. Added several items to QListWidget and then set the QListView's model to QListWidget::model();
    Then I set both's
    and what I get is that QListWidget works properly (it does'n scroll anywhere, and the moved item stays selected) but QListView doesn't behave the same way (it scrolls to top and selects eithe the index item used to be at or the one right next to where it was depending on moving the item up or down the list).
    Seem like I just don't know something about it but I can't find the answer to this.

  • Lifetime Qt Champion

    QListWidget reimplements the dropEvent method so it might be that.

    Did you have a look at the "bug report system": ? Somebody might already have posted something about it, if not you could consider open a new bug report providing a minimal compilable example that show the behavior

  • Lifetime Qt Champion

  • actual in qt5.11
    it seem what glitch happens within
    or so...

    QAbstractItemView::rowsAboutToBeRemoved(parent, start, end);

    CollapsingState... for qlistview ???

    workaround for some cases

    class listviewscrollfix: public QListView{...}
    void listviewscrollfix::rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end)
    //    Q_D(QListView);
    //    // if the parent is above d->root in the tree, nothing will happen
        ///QAbstractItemView::rowsAboutToBeRemoved(parent, start, end);
            setState(NoState);/// !!! CollapsingState ///main glitch reason 
            // Ensure one selected item in single selection mode.
            QModelIndex current = currentIndex();
            if (selectionMode() == SingleSelection
                && current.isValid()
                && current.row() >= start
                && current.row() <= end
                && current.parent() == parent) {
                int totalToRemove = end - start + 1;
                if (model()->rowCount(parent) <= totalToRemove) { // no more children
                    QModelIndex index = parent;
    ///we dont have access to some metods so skipped
    //                while (index != d->root && !d->isIndexEnabled(index))
    //                    index = index.parent();
    //                if (index != d->root)
                } else {
                    ///we dont have access to some metods so skipped
    //                int row = end + 1;
    //                QModelIndex next;
    //                do { // find the next visible and enabled item
    //                    next = d->model->index(row++, current.column(), current.parent());
    //                } while (next.isValid() && (isIndexHidden(next) || !d->isIndexEnabled(next)));
    //                if (row > d->model->rowCount(parent)) {
    //                    row = start - 1;
    //                    do { // find the previous visible and enabled item
    //                        next = d->model->index(row--, current.column(), current.parent());
    //                    } while (next.isValid() && (isIndexHidden(next) || !d->isIndexEnabled(next)));
    //                }
    //                setCurrentIndex(next);
            ///we dont have access to some metods & and our list not editable so skipped
            // Remove all affected editors; this is more efficient than waiting for updateGeometries() to clean out editors for invalid indexes
    //        QEditorIndexHash::iterator i = d->editorIndexHash.begin();
    //        while (i != d->editorIndexHash.end()) {
    //            const QModelIndex index = i.value();
    //            if (index.row() >= start && index.row() <= end && d->model->parent(index) == parent) {
    //                QWidget *editor = i.key();
    //                QEditorInfo info = d->indexEditorHash.take(index);
    //                i = d->editorIndexHash.erase(i);
    //                if (info.widget)
    //                    d->releaseEditor(editor, index);
    //            } else {
    //                ++i;
    //            }
    //        }
        ///we dont have access to some metods & we dont have hidden rows so skipped
    //    if (parent == d->root) {
    //        QSet<QPersistentModelIndex>::iterator it = d->hiddenRows.begin();
    //        while (it != d->hiddenRows.end()) {
    //            int hiddenRow = it->row();
    //            if (hiddenRow >= start && hiddenRow <= end) {
    //                it = d->hiddenRows.erase(it);
    //            } else {
    //                ++it;
    //            }
    //        }
    //    }
    //    d->clear();//???
    //    d->doDelayedItemsLayout();

    or just

    void listviewscrollfix::rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end){}


    bool SomeListModel::removeRows(int row, int count, const QModelIndex &parent)
        if (parent.isValid())
            return false;
        for (int i = 0; i != count; ++i){
                beginRemoveRows(parent, row, row);
            someitemcontainer.removeAt(row);//for small listst it will be ok 1 by 1
                dataChanged(index(row),index(row));//scroll glitch workaround...dont ask why so...//for update scrollbar max value
        return true;

Log in to reply