Drag and Drop between 3 QListViews



  • Hi all,

    I try to realize a drag and drop system between 3 QListViews, I thought about subclassing QAbstractListModel, each model inherits a QList<int>. I already searched around for solutions, but I didnt found any good example or explanation. What I already know is that I have to reimplement the functions in QAbstractListModel:

    • rowCount()
    • data()
    • setData()
    • headerData()

    About the following I am not sure

    • mimeTypes()
    • mimeData()
    • dropMimeData()
    • supportedDropActions()

    I think I also need a subclass of QListView and implement the following or don't I need to subclass ?

    • setAcceptDrops(true);
    • setDragEnabled(true);
    • setDragDropMode(QAbstractItemView::InternalMove);
    • setDropIndicatorShown(true);
    • setSelectionMode(QAbstractItemView::SingleSelection);
    • setDragDropMode(QAbstractItemView::DragDrop);

    My problem is I didnt found any implementation examples of any mime or drop method. Also the user shouldn't be able to drop a item outside of a QListView, if he does so it should drop back from where it came.
    Has anybody a good implementation for these methods?



  • I think this is a very good introduction into the topic: http://doc.qt.nokia.com/4.7-snapshot/model-view-programming.html#using-drag-and-drop-with-item-views

    Other than that, have a look at those examples on how to implement Drag and Drop:
    http://doc-snapshot.qt-project.org/4.8/examples-draganddrop.html

    How to subclass the actual model is being demontrated in multiple examples here: http://doc-snapshot.qt-project.org/4.8/examples-itemviews.html

    And last but not least, the documentation talks a little about mime-data in models: http://qt-project.org/doc/qt-4.8/qabstractitemmodel.html#mimeData



  • Ok, I read the articles you linked and implement the methods sofar. -But if I try to drag an item from one to another View it shows a crossed circle.-
    Edit: Ok i can drag things around, but I am not possible to drop them:(
    @ QList<int> list;
    list << 2;
    list << 4;
    list << 5;

    MODEL *model = new MODEL();
    model->setPlayers(list);
    ui->NotPossibleList->setModel(model);
    ui->NotPossibleList->setAcceptDrops(true);
    ui->NotPossibleList->setDragDropMode(QAbstractItemView::InternalMove);
    ui->NotPossibleList->setDropIndicatorShown(true);
    ui->NotPossibleList->setSelectionMode(QAbstractItemView::SingleSelection);
    ui->NotPossibleList->setDragEnabled(true);
    ui->NotPossibleList->viewport()->setAcceptDrops(true);
    ui->NotPossibleList->setDropIndicatorShown(true);
    ui->NotPossibleList->setDragDropMode(QAbstractItemView::DragDrop);
    
    MODEL *model2 = new MODEL();
    model2->setPlayers(QList<int>());
    ui->PresentList->setModel(model2);
    ui->PresentList->setAcceptDrops(true);
    ui->PresentList->setDragDropMode(QAbstractItemView::InternalMove);
    ui->PresentList->setDropIndicatorShown(true);
    ui->PresentList->setSelectionMode(QAbstractItemView::SingleSelection);
    ui->PresentList->setDragEnabled(true);
    ui->PresentList->viewport()->setAcceptDrops(true);
    ui->PresentList->setDropIndicatorShown(true);
    ui->PresentList->setDragDropMode(QAbstractItemView::DragDrop);@
    

    The implementation of the model.

    @#include "model.h"

    MODEL::MODEL()
    {
    manager = MANAGER::getInstance();
    }

    int MODEL::rowCount(const QModelIndex &parent) const
    {
    return parent.isValid() ? 0 : players.size();
    }

    QVariant MODEL::data(const QModelIndex &index, int role) const
    {
    if (!index.isValid() ||
    index.row() < 0 || index.row() >= players.size() ||
    index.column() < 0 || index.column() >= 1)
    return QVariant();

    if (role == Qt::DisplayRole && index.column() == 0)
    {
        return manager->getPlayer(players[index.row()])->name();
    }
    
    return QVariant();
    

    }

    bool MODEL::setData(const QModelIndex &index, const QVariant &value, int role)
    {
    if (!index.isValid() ||
    index.row() < 0 || index.row() >= players.size() ||
    index.column() < 0 || index.column() >= 1)
    return false;

    if (role == Qt::UserRole)
    {
        players.insert(index.row(), value.toInt());
    }
    
    emit dataChanged(index, index);
    return true;
    

    }

    QVariant MODEL::headerData(int section, Qt::Orientation orientation, int role) const
    {
    if (role != Qt::DisplayRole)
    return QVariant();

    if (orientation == Qt::Horizontal && section >= 1)
    {
        return tr("Player");
    }
    
    return QVariant();
    

    }

    Qt::ItemFlags MODEL::flags(const QModelIndex &index) const
    {
    Qt::ItemFlags defaultFlags = Qt::ItemIsSelectable | Qt::ItemIsEnabled;

    if (index.isValid())
        return Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | defaultFlags;
    else
        return Qt::ItemIsDropEnabled | defaultFlags;
    

    }

    QStringList MODEL::mimeTypes()
    {
    QStringList types;
    types << "application/vnd.text.list";
    return types;
    }

    QMimeData* MODEL::mimeData(const QModelIndexList &indexes) const
    {
    QMimeData *mimeData = new QMimeData();
    QByteArray encodedData;

    QDataStream stream(&encodedData, QIODevice::WriteOnly);
    
    foreach (const QModelIndex &index, indexes) {
        if (index.isValid())
        {
            QString text = data(index, Qt::UserRole).toString();
            stream << text;
        }
    }
    
    mimeData->setData("application/vnd.text.list", encodedData);
    return mimeData;
    

    }

    bool MODEL::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent)
    {
    if (action == Qt::IgnoreAction)
    return true;

    if (!data->hasFormat("application/vnd.text.list"))
        return false;
    
    if (column > 0)
        return false;
    
    int beginRow;
    
    if (row != -1)
        beginRow = row;
    else if (parent.isValid())
        beginRow = parent.row();
    else
        beginRow = rowCount(QModelIndex());
    
    QByteArray encodedData = data->data("application/vnd.text.list");
    QDataStream stream(&encodedData, QIODevice::ReadOnly);
    QStringList newItems;
    int rows = 0;
    
    while (!stream.atEnd())
    {
        QString text;
        stream >> text;
        newItems << text;
        ++rows;
    }
    
    insertRows(beginRow, rows, QModelIndex());
    foreach (const QString &text, newItems)
    {
        QModelIndex idx = index(beginRow, 0, QModelIndex());
        setData(idx, text, Qt::UserRole);
        beginRow++;
    }
    
    return true;
    

    }

    Qt::DropActions MODEL::supportedDropActions()
    {
    return Qt::CopyAction | Qt::MoveAction;
    }

    void MODEL::setPlayers(QList<int> players)
    {
    this->players = players;
    }

    QList<int> MODEL::getPlayers()
    {
    return players;
    }
    @

    Is there any thing which I forgot to implement or failed to implement?



  • Sorry, that I have to push it up again, but I am still stuck at this problem. My actual code looks like this:
    @

    MODEL::MODEL()
    {
    manager = MANAGER::getInstance();
    }

    int MODEL::rowCount(const QModelIndex &parent) const
    {
    return parent.isValid() ? 0 : list.size();
    }

    QVariant MODEL::data(const QModelIndex &index, int role) const
    {
    if (!index.isValid() ||
    index.row() < 0 || index.row() >= list.size() ||
    index.column() < 0 || index.column() >= 1)
    return QVariant();

    if (role == Qt::DisplayRole && index.column() == 0)
    {
        return manager->findEntry(list[index.row()])->getName();
    }
    
    return QVariant();
    

    }

    bool MODEL::setData(const QModelIndex &index, const QVariant &value, int role)
    {
    if (!index.isValid() ||
    index.row() < 0 || index.row() >= list.size() ||
    index.column() < 0 || index.column() >= 1)
    return false;

    if (role == Qt::UserRole)
    {
        list[index.row()] = value.toInt();
    }
    
    emit dataChanged(index, index);
    return true;
    

    }

    QVariant MODEL::headerData(int section, Qt::Orientation orientation, int role) const
    {

    return QVariant();
    

    }

    bool MODEL::insertRows(int row, int count, const QModelIndex &parent)
    {
    beginInsertRows(QModelIndex(), row, row + count - 1);

    for (int i = 0; i < count; i++)
    {
        list.insert(row, -1);
    }
    
    endInsertRows();
    return true;
    

    }

    bool MODEL::removeRows(int row, int count, const QModelIndex &parent)
    {
    beginRemoveRows(QModelIndex(), row, row + count - 1);

    for (int i = 0; i < count; i++)
    {
        list.removeAt(row);
    }
    
    endRemoveRows();
    return true;
    

    }

    Qt::ItemFlags MODEL::flags(const QModelIndex &index) const
    {
    Qt::ItemFlags defaultFlags = Qt::ItemIsSelectable | Qt::ItemIsEnabled;

    if (index.isValid())
        return Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | defaultFlags;
    else
        return Qt::ItemIsDropEnabled | defaultFlags;
    

    }

    QStringList MODEL::mimeTypes()
    {
    QStringList types;
    types << "application/vnd.text.list";
    return types;
    }

    QMimeData* MODEL::mimeData(const QModelIndexList &indexes) const
    {
    QMimeData *mimeData = new QMimeData();
    QByteArray encodedData;

    QDataStream stream(&encodedData, QIODevice::WriteOnly);
    
    foreach (const QModelIndex &index, indexes) {
        if (index.isValid())
        {
            QString text = data(index, Qt::DisplayRole).toString();
            stream << text;
        }
    }
    
    mimeData->setData("application/vnd.text.list", encodedData);
    return mimeData;
    

    }

    bool MODEL::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent)
    {
    if (action == Qt::IgnoreAction)
    return true;

    if (!data->hasFormat("application/vnd.text.list"))
        return false;
    
    if (column > 0)
        return false;
    
    int beginRow;
    
    if (row != -1)
        beginRow = row;
    else if (parent.isValid())
        beginRow = parent.row();
    else
        beginRow = rowCount(QModelIndex());
    
    QByteArray encodedData = data->data("application/vnd.text.list");
    QDataStream stream(&encodedData, QIODevice::ReadOnly);
    QStringList newItems;
    int rows = 0;
    
    while (!stream.atEnd())
    {
        QString text;
        stream >> text;
        newItems << text;
        ++rows;
    }
    
    insertRows(beginRow, rows, QModelIndex());
    foreach (const QString &text, newItems)
    {
        QModelIndex idx = index(beginRow, 0, QModelIndex());
        setData(idx, text, Qt::UserRole);
        beginRow++;
    }
    
    return true;
    

    }

    Qt::DropActions MODEL::supportedDropActions() const
    {
    return Qt::MoveAction;
    }

    void MODEL::setList(QList<int> list)
    {
    this->list = list;
    }

    QList<int> MODEL::getList()
    {
    return list;
    }
    @

    In my mainwindow.cpp
    @ MODEL*model = new MODEL();
    model->setPlayers(list);
    ui->NotPossibleList->setModel(model);
    ui->NotPossibleList->setSelectionMode(QAbstractItemView::ExtendedSelection);
    ui->NotPossibleList->setDragEnabled(true);
    ui->NotPossibleList->setAcceptDrops(true);
    ui->NotPossibleList->setDropIndicatorShown(true);
    @


Log in to reply
 

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