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.htmlHow 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);
@