1、实现:需要对以下四个虚函数重写
Qt::DropActions supportedDropActions() const override;//设置支持放入动作
QStringList mimeTypes() const override;//设置在拖放操作中导出的条目的数据的编码类型
QMimeData *mimeData(const QModelIndexList &indexes) const override;//将数据放入QMimeData中
//将拖放的数据放入模型中
bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) override;
2、示例源码:
//widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QAbstractListModel>
#include <QStringList>
//简单的、非层次结构的数据模型
class Widget : public QAbstractListModel
{
Q_OBJECT
public:
Widget(const QStringList &strings, QObject *parent = 0);
~Widget();
//非层次结构,不需要考虑父子关系
//如果模型是层次结构的,还需要实现index()和parent()函数
//只读模型,需要实现的函数
int rowCount(const QModelIndex &parent = QModelIndex()) const override;//返回模型行数
QVariant data(const QModelIndex &index, int role) const override;//返回指定模型索引的数据项
//在树和表格视图的标头显示一些内容
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
//将各种操作转换为对具体数据源的操作,从而对外提供一个统一的接口
//实现界面可编辑,需要实现的函数
//模型让委托知道项目是可编辑的,这里为每个项目返回一个正确的标识
Qt::ItemFlags flags(const QModelIndex &index) const override;
//为委托向模型中设置数据提供一条途径
bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override;
//实现在模型中插入和删除行,需要实现的函数
bool insertRows(int position, int rows, const QModelIndex &index = QModelIndex()) override;
bool removeRows(int position, int rows, const QModelIndex &index = QModelIndex()) override;
//视图中显示数据由模型控制,为使用的模型提供拖放操作的支持
Qt::DropActions supportedDropActions() const override;//设置支持放入动作
QStringList mimeTypes() const override;//设置在拖放操作中导出的条目的数据的编码类型
QMimeData *mimeData(const QModelIndexList &indexes) const override;//将数据放入QMimeData中
//将拖放的数据放入模型中
bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) override;
private:
//QAbstractItemModel本身不存储任何数据,仅提供一些接口来供视图访问数据
//string_list_作为内部数据源
QStringList string_list_;
};
#endif // WIDGET_H
//widget.cpp
#include "widget.h"
#include <QMimeData>
#include <QDataStream>
Widget::Widget(const QStringList &strings, QObject *parent)
: QAbstractListModel(parent), string_list_(strings)
{
}
Widget::~Widget()
{
}
int Widget::rowCount(const QModelIndex &parent) const
{
return string_list_.count();
}
QVariant Widget::data(const QModelIndex &index, int role) const
{
if(!index.isValid()){
return QVariant();
}
if(index.row() >= string_list_.size()){
return QVariant();
}
if(role == Qt::DisplayRole || role == Qt::EditRole){
return string_list_.at(index.row());
}else {
return QVariant();
}
}
QVariant Widget::headerData(int section, Qt::Orientation orientation, int role) const
{
if(role != Qt::DisplayRole){
return QVariant();
}
if(orientation == Qt::Horizontal){
return QString("Column %1").arg(section);
}else {
return QString("Row %1").arg(section);
}
}
Qt::ItemFlags Widget::flags(const QModelIndex &index) const
{
//如果该索引无效,只支持放入操作
if(!index.isValid()){
return Qt::ItemIsEnabled | Qt::ItemIsDropEnabled;
}
//如果该索引有效,那么既支持拖拽操作,也支持放入操纵
return QAbstractItemModel::flags(index) | Qt::ItemIsEditable | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled;
}
bool Widget::setData(const QModelIndex &index, const QVariant &value, int role)
{
//保证索引是有效的、项目是正确的类型、角色是被支持的
if(index.isValid() && role == Qt::EditRole){
string_list_.replace(index.row(), value.toString());
emit dataChanged(index, index);
return true;
}
return false;
}
bool Widget::insertRows(int position, int rows, const QModelIndex &index)
{
//告知其他组件指定的行将要发生改变
beginInsertRows(QModelIndex(), position, position + rows -1);//父项的模型索引,要插入的第一个、最后一个新行的行号
for(int row = 0; row < rows; ++row){
string_list_.insert(position, "");//添加空的字符串
}
//告知其他组件该模型大小发生了变化
endInsertRows();
return true;
}
bool Widget::removeRows(int position, int rows, const QModelIndex &index)
{
beginRemoveRows(QModelIndex(), position, position + rows -1);
for(int row = 0; row < rows; ++row){
string_list_.removeAt(position);
}
endRemoveRows();
return true;
}
Qt::DropActions Widget::supportedDropActions() const
{
return Qt::CopyAction | Qt::MoveAction;//复制和移动
}
QStringList Widget::mimeTypes() const
{
//当在拖放操作中的数据项从模型中导出时,要被编码为合适的格式来对应一个或多个MIME类型
QStringList types;
//application/vnd.text.list是自定义的类型,后面的函数中要保持一致
types << "application/vnd.text.list";//此处只支持纯文本类型
return types;
}
QMimeData *Widget::mimeData(const QModelIndexList &indexes) const
{
//在进行拖放操作之前,需要将数据放入到一个QMimeData类型的对象中
QMimeData *mime_data = new QMimeData();
QByteArray encoded_data;
QDataStream stream(&encoded_data, QIODevice::WriteOnly);
foreach(const QModelIndex &index, indexes){
if(index.isValid()){
QString text = data(index, Qt::DisplayRole).toString();
stream << text;
}
}
//将数据放入QMimeData中
mime_data->setData("application/vnd.text.list", encoded_data);
return mime_data;
}
bool Widget::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent)
{
//如果放入的动作是Qt::IgnoreAction,那么返回true
if(action == Qt::IgnoreAction){
return true;
}
//如果数据的格式不是指定的格式,返回false
if(!data->hasFormat("application/vnd.text.list")){
return false;
}
//因为这里是列表,只用一列,,所以列大于0时,返回false
if(column >0){
return false;
}
//设置开始插入的行
int begin_row;
if(row != -1){
begin_row = row;
}else if(parent.isValid()){
begin_row = parent.row();
}else{
begin_row = rowCount(QModelIndex());
}
//将数据从QMimeData中读出来,然后插入到模型中
QByteArray encoded_data = data->data("application/vnd.text.list");
QDataStream stream(&encoded_data, QIODevice::ReadOnly);
QStringList new_items;
int rows = 0;
while(!stream.atEnd()){
QString text;
stream >> text;
new_items << text;
++rows;
}
insertRows(begin_row, rows, QModelIndex());
foreach(const QString &text, new_items){
QModelIndex idx = index(begin_row, 0, QModelIndex());
setData(idx, text);
begin_row++;
}
return true;
}
//main.cpp
#include "widget.h"
#include <QApplication>
#include <QTableView>
#include <QListView>
#include <QDebug>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QStringList list;
list << "a" << "b" << "c";
Widget model(list);
QListView listView;
listView.setModel(&model);
listView.setSelectionMode(QAbstractItemView::ExtendedSelection);
listView.setDragEnabled(true);
listView.setAcceptDrops(true);
listView.setDropIndicatorShown(true);
listView.show();
//添加和删除
model.insertRows(3,2);
model.removeRows(0,1);
return a.exec();
}