gpt4 book ai didi

Qt:如何使用自定义模型实现简单的内部拖放以重新排序 QListView 中的项目

转载 作者:行者123 更新时间:2023-12-04 11:51:04 26 4
gpt4 key购买 nike

我有一个 QList自定义结构,我正在使用自定义模型类( QAbstractListModel 的子类)在一维 QListView 中显示这些结构。我已经覆盖了方法 rowCount , flagsdata从结构元素构造一个显示字符串。

现在我想启用内部拖放,以便能够通过将它们拖放到其他项目之间来重新排序列表中的项目,但这项任务似乎非常复杂。我究竟需要覆盖什么以及我需要设置哪些参数?我尝试了很多东西,我试过了

view->setDragEnabled( true );
view->setAcceptDrops( true );
view->setDragDropMode( QAbstractItemView::InternalMove );
view->setDefaultDropAction( Qt::MoveAction );

我试过
Qt::DropActions supportedDropActions() const override {
return Qt::MoveAction;
}
Qt::ItemFlags flags( const QModelIndex & index ) const override{
return QAbstractItemModel::flags( index ) | Qt::ItemIsDragEnabled;
}

我尝试实现 insertRowsremoveRows ,但它仍然不起作用。

我还没有找到完全这样做的代码示例。官方文档非常深入地介绍了 View /模型模式的工作原理以及如何从外部应用程序或其他小部件进行拖放,但我不想要任何这些。我只需要简单的内部拖放操作来手动重新排序该 ListView 中的项目。

有人可以帮帮我吗?否则我会因此而发疯。

编辑:根据要求添加 insertRows/removeRows 实现:
bool insertRows( int row, int count, const QModelIndex & parent ) override
{
QAbstractListModel::beginInsertRows( parent, row, row + count - 1 );

for (int i = 0; i < count; i++)
AObjectListModel<Object>::objectList.insert( row, Object() );

QAbstractListModel::endInsertRows();
return true;
}

bool removeRows( int row, int count, const QModelIndex & parent ) override
{
if (row < 0 || row + count > AObjectListModel<Object>::objectList.size())
return false;

QAbstractListModel::beginRemoveRows( parent, row, row + count - 1 );

for (int i = 0; i < count; i++)
AObjectListModel<Object>::objectList.removeAt( row );

QAbstractListModel::endRemoveRows();
return true;
}
objectList是 QList,其中 Object 是模板参数。

最佳答案

当您想重新组织自定义模型中的项目时,您必须实现所有需要的操作:
- 如何插入和删除一行
- 如何获取和设置数据
- 如何序列化项目(构建 mimedata)
- 如何反序列化项目

带有 QStringList 的自定义模型的示例作为数据源:

模型的最小实现应该是:

class CustomModel: public QAbstractListModel
{
public:
CustomModel()
{
internalData = QString("abcdefghij").split("");
}
int rowCount(const QModelIndex &parent) const
{
return internalData.length();
}
QVariant data(const QModelIndex &index, int role) const
{
if (!index.isValid() || index.parent().isValid())
return QVariant();
if (role != Qt::DisplayRole)
return QVariant();
return internalData.at(index.row());
}
private:
QStringList internalData;
};

我们必须添加插入/删除行和设置数据的方式:
    bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::DisplayRole)
{
if (role != Qt::DisplayRole)
return false;
internalData[index.row()] = value.toString();
return true;
}
bool insertRows(int row, int count, const QModelIndex &parent)
{
if (parent.isValid())
return false;
for (int i = 0; i != count; ++i)
internalData.insert(row + i, "");
return true;
}
bool removeRows(int row, int count, const QModelIndex &parent)
{
if (parent.isValid())
return false;
beginRemoveRows(parent, row, row + count - 1);
for (int i = 0; i != count; ++i)
internalData.removeAt(row);
endRemoveRows();
return true;
}

对于拖放部分:

首先,我们需要定义一个 mime 类型来定义反序列化数据的方式:
    QStringList mimeTypes() const
{
QStringList types;
types << CustomModel::MimeType;
return types;
}

哪里 CustomModel::MimeType是一个常量字符串,如 "application/my.custom.model"
方法 canDropMimeData将用于检查丢弃的数据是否合法。所以,我们可以丢弃外部数据:
    bool canDropMimeData(const QMimeData *data,
Qt::DropAction action, int /*row*/, int /*column*/, const QModelIndex& /*parent*/)
{
if ( action != Qt::MoveAction || !data->hasFormat(CustomModel::MimeType))
return false;
return true;
}

然后,我们可以根据内部数据创建我们的 mime 数据:
    QMimeData* mimeData(const QModelIndexList &indexes) const
{
QMimeData* mimeData = new QMimeData;
QByteArray encodedData;

QDataStream stream(&encodedData, QIODevice::WriteOnly);

for (const QModelIndex &index : indexes) {
if (index.isValid()) {
QString text = data(index, Qt::DisplayRole).toString();
stream << text;
}
}
mimeData->setData(CustomModel::MimeType, encodedData);
return mimeData;
}

现在,我们必须处理丢弃的数据。我们必须反序列化 mime 数据,插入一个新行以将数据设置在正确的位置(对于 Qt::MoveAction ,旧行将被自动删除。这就是为什么我们必须实现 removeRows ):
bool dropMimeData(const QMimeData *data,
Qt::DropAction action, int row, int column, const QModelIndex &parent)
{
if (!canDropMimeData(data, action, row, column, parent))
return false;

if (action == Qt::IgnoreAction)
return true;
else if (action != Qt::MoveAction)
return false;

QByteArray encodedData = data->data("application/my.custom.model");
QDataStream stream(&encodedData, QIODevice::ReadOnly);
QStringList newItems;
int rows = 0;

while (!stream.atEnd()) {
QString text;
stream >> text;
newItems << text;
++rows;
}

insertRows(row, rows, QModelIndex());
for (const QString &text : qAsConst(newItems))
{
QModelIndex idx = index(row, 0, QModelIndex());
setData(idx, text);
row++;
}

return true;
}

如果您想了解有关 Qt 中拖放系统的更多信息,请查看 the documentation .

关于Qt:如何使用自定义模型实现简单的内部拖放以重新排序 QListView 中的项目,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56819085/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com