QListView & item movement



  • Hi,
    I have a QListView and it's a listview for showing the queue in my music player project. I have two problems:

    first: i want the user to be able to move the items up and down by draging and droping them. I set the dragDropMode to internalMove and the dafaultDropAction to targetMoveAcion but when I run the app and move the items they go into each other.
    what can I do about that? (QListWidget doesn't have this problem)

    second: I need to know which Item is moved and where is it moved to so I can be able to update the QMediaPlayer->playList(). how can I do that?


  • Lifetime Qt Champion

    Hi,

    What do you mean by "they go into each other" ?

    You can use the indexesMoved method to get the information and rebuild the playlist from there.



  • @SGaist I mean when you move the Item in QListView you can drop the item between two items or on another item. when you drop it on another item the other item disappears and the moved item takes its place. I think it replaces the item's data

    and also I need to know where the index is moved to. is that possible?


  • Lifetime Qt Champion

    Are you using the QListView in Icon mode or List mode ?



  • @SGaist I'm using it in list mode


  • Lifetime Qt Champion

    Can you share how you setup your QListView ?



  • @SGaist
    I create a queueModel and set the listView's model to queue model. the Items in queueModel have a few userRole data. this is the slot that connets to doubleClicked signal on a track that I have in my trackModel:

    for (int i=0; i<trackModel->rowCount(); ++i)
    {
    queueModel->setItem(i, trackModel->item(i)->clone());

        const QPixmap *artWork = new QPixmap;
        artWork = ui->trackArtLabel->pixmap();
        queueModel->item(i)->setIcon(QIcon(*artWork));
    
        QString itemTitle=QString("%1\n%2\n%3")
                .arg(queueModel->item(i)->data(Qt::UserRole+3).toString())
                .arg(queueModel->item(i)->data(Qt::UserRole+4).toString())
                .arg(queueModel->item(i)->data(Qt::UserRole+6).toString());
    
        queueModel->item(i)->setText(itemTitle);
    }
    
    for (int i=0; i<queueModel->rowCount(); ++i)
    {
        mediaPlayer.playlist()->addMedia(QMediaContent(QUrl::fromLocalFile(queueModel->item(i)->data(Qt::UserRole+1).toString())));
    }
    
    playQueue(item.data(Qt::UserRole+7).toInt());

  • Lifetime Qt Champion

    You have a memory leak here. You allocate artWork on the heap and then directly replace its value by the one from trackArtLabel's pixmap. There's no need for that allocation.

    Is your queueModel a custom model ?



  • @SGaist
    yes you are right. I'm using QStandardItemModel



  • Any help would be appreciated.


  • Lifetime Qt Champion

    Again, can you show how you initialize your QListView and your model ?



  • Hi, @SGaist I'm sorry I didn't get the question in the first place
    the QListview is initialized from the ui with these

    queueView->setObjectName(QStringLiteral("queueView"));
    queueView->setEnabled(true);
    queueView->setFrameShape(QFrame::NoFrame);
    queueView->setFrameShadow(QFrame::Plain);
    queueView->setSizeAdjustPolicy(QAbstractScrollArea::AdjustIgnored);
    queueView->setEditTriggers(QAbstractItemView::NoEditTriggers);
    queueView->setDragEnabled(false);
    queueView->setDragDropMode(QAbstractItemView::InternalMove);
    queueView->setDefaultDropAction(Qt::TargetMoveAction);
    queueView->setAlternatingRowColors(false);
    queueView->setSelectionBehavior(QAbstractItemView::SelectItems);
    queueView->setIconSize(QSize(150, 150));
    queueView->setMovement(QListView::Snap);
    queueView->setResizeMode(QListView::Adjust);
    queueView->setSpacing(0);
    queueView->setViewMode(QListView::ListMode);
    queueView->setModelColumn(0);

    and the model:

    QStandardItemModel *queueModel;
    

    queueModel = new QStandardItemModel(this);

    ui->queueView->setModel(queueModel);



  • Ideally you want the dragged item to be placed between existing items, right? You can change standard item flags to disable drops. (ItemIsDropEnabled).

    And for getting new index perhaps you can use itemChanged signal?



  • Hi @asanka424
    I tried the Qt::itemIsDropEnabled but the Items in the model get disabled. what should I do?



  • @shahriar25
    Hi,
    Did you disable drops in QStandardItem or ListView? You have to disable drops in QStandardItem not in the view
    setDropEnabled(false)

    BTW if you want to implement more custom behaviours I encourage to use QAbstractItemModel where you have more control over these operations.

    Thanks



  • @asanka424
    Hi,
    I did this in a "for" for every Item:

    queueModel->item(i)->setFlags(Qt::ItemIsDropEnabled);

    And also I used QStandardModel in my app a lot but if this thing that I want can't be done in QStandardModel I will have to change the model. And also note that QListWidget doesn't have this problem



  • this will enable drops in each item in your model. what you should do is disabling it like this

    item->setFlags(item->flags() ^ Qt::ItemIsDropEnabled)



  • Hi @asanka424 @SGaist
    I was able to set the item flags correctly but now I'm having problem with item changed signal.
    How do I know where was the Item (it's row) before it was moved? (I can set the item's data to hold the current row but isn't there a better way?)

    And also I was searching the QStandardItemModel's signals to find something useful and I found QStandardItemModel::rowsMoved(...) and QStandardItemModel::rowsAboutToBeMoved(...) and I tried them but they don't ge triggred when an item is moved. why is that?



  • You can try dataChanged signal but it won't identify moves explicitly.

    BTW does drag and drop work as you expected now?



  • Hi @asanka424
    Yes it does. if it won't work then I will have to set the user data every time an item moves. but I think there has to be another way.


  • Qt Champions 2016

    @asanka424

    what you should do is disabling it like this

    item->setFlags(item->flags() ^ Qt::ItemIsDropEnabled)
    

    Beware of such handling of flags!

    It's a very wrong way to do it. If the flag is not set you'll actually enable it, additionally it doesn't work with compound flags! Suppose you have (in binary) a = 010 and b = 110, then a ^ b == 100 which is very different from the expected 000.

    The proper way to remove a set of bits is to AND the inversion: a & ~b == 000
    /and this can be rigorously proven to be different from a ^ b if you expand the xor in the other basic operations a ^ b = (a & ~b) | (~a & b)/



  • Hi @kshegunov . Thank you for correcting that I cahnged my code.
    I tried the item changed flag and the data of item but it didn't work. I really don't know what to do


  • Qt Champions 2016

    @shahriar25
    Well I don't know, I can't spot anything plainly wrong, although there isn't much code to begin with. However, this line:

    queueView->setDragEnabled(false);
    

    does look suspicious, have you removed it as it had been suggested, because it's not clear from your answer to @asanka424's question.



  • @kshegunov
    Yes agree with you. I just replied for the context where I knew the flag is set.



  • Hi @asanka424 @kshegunov
    Sorry for replying late.
    an interesting thing happened:
    when I set the flags of the items to
    queueModel->item(i)->setFlags(queueModel->item(i)->flags() & !Qt::ItemIsDropEnabled);
    the items get disabled!
    bot when I do:
    queueModel->item(i)->setFlags(queueModel->item(i)->flags() ^ Qt::ItemIsDropEnabled);
    the is no problem. I think I'm doing something wrong.

    ANd I will try:
    queueView->setDragEnabled(false);
    and get back with a result. thank all of you for answering again. I love this from and the people who answer the questions



  • Hi,
    I tried this:
    queueView->setDragEnabled(false);
    and it didn't work.

    this problem isn't fixable :( :(


  • Lifetime Qt Champion

    One thing you can try: start by setting the view mode or don't set it at all since you are using the default mode.



  • Hi,
    I gave up moving the items by drag and droping them
    Now I want to put move up and move down buttons
    How can I move a selected index one item up or down?



  • Hi, I put two buttons for moving items up and down but when the buttons are pressed the listView goes out of focus and the selected items don't remain selected. how can I fix this?

    and also how can I swap children of a QDomElement?


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.