Bonjour,

J'essaye en vain d'implémenter la réorganisation des éléments d'une QListView par glisser déposer. Mais il semble que quelque chose m'échappe. En effet lorsque je veux déplacer un éléments dans la liste en le glissant dans ma liste, j'obtiens toujours un icône d'interdiction qui s'affiche (voir image plus bas).

Pour le modèle de la liste, j'ai crée une classe "DeviceListModel" qui dérive de QAbstractListModel et j'ai réimplémenté les fonctions nécessaires (certaines renvoi simplement true et ne font rien, je n'ai pas pris le temps de les implémenter et ce n'est pas nécessaire car elle ne sont jamais appelées dans ce cas précis).

Pourtant d'après la doc ainsi que les dizaines de forums que j'ai consulté, je pense avoir tout configuré correctement.

Voici mon code :

MainWindow.cpp:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
 
    ui->listView->setSelectionMode(QAbstractItemView::SingleSelection);
    ui->listView->setMovement(QListView::Free);
    ui->listView->setDragEnabled(true);
    ui->listView->viewport()->setAcceptDrops(true);
    ui->listView->setDropIndicatorShown(true);
    //on accepte que les déplacements en interne
    ui->listView->setDragDropMode(QAbstractItemView::InternalMove);
 
    DeviceListModel *model = new DeviceListModel(this);
    model->setList(QString("Value1|Value2|Value3|Value4|Value5|Value6|Value7|Value8|Value9").split("|"));
    ui->listView->setModel(model);
}
 
MainWindow::~MainWindow()
{
    delete ui;    
}
DeviceListModel.h:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class DeviceListModel : public QAbstractListModel
{
    Q_OBJECT
public:
    explicit DeviceListModel(QObject *parent = 0);
 
    void setList(const QList<QString> &list);
 
    //Reimplement needed functions
    int rowCount(const QModelIndex &parent) const;
    QVariant data(const QModelIndex &index, int role) const;
    virtual Qt::DropActions supportedDragActions();
    virtual Qt::DropActions supportedDropActions();
    Qt::ItemFlags flags(const QModelIndex &index) const;
 
    bool dropMimeData(const QMimeData *data, Qt::DropAction action, 
                      int row, int column, const QModelIndex &parent);
    bool insertRows(int row, int count, const QModelIndex &parent);
    bool removeRows(int row, int count, const QModelIndex &parent);
    bool setData(const QModelIndex &index, const QVariant &value, int role);
 
protected:
    QList<QString> m_list;
};
DeviceListModel.cpp:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
DeviceListModel::DeviceListModel(QObject *parent) :
    QAbstractListModel(parent)
{
}
 
int DeviceListModel::rowCount(const QModelIndex &parent) const
{
    Q_UNUSED(parent);
    return m_list.count();
}
 
QVariant DeviceListModel::data(const QModelIndex &index, int role) const
{
    if (index.row() < 0 || index.row() >= m_list.size())
           return QVariant();
 
       if (role == Qt::DisplayRole || role == Qt::EditRole)
           return m_list.value(index.row());
 
       return QVariant();
}
 
Qt::DropActions DeviceListModel::supportedDragActions()
{
    qDebug() << "supportedDragActions " << QAbstractListModel::supportedDragActions();
    return Qt::CopyAction | Qt::MoveAction;
}
 
Qt::DropActions DeviceListModel::supportedDropActions()
{
    return Qt::CopyAction | Qt::MoveAction;
}
 
Qt::ItemFlags DeviceListModel::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;
}
 
bool DeviceListModel::dropMimeData(const QMimeData *data, Qt::DropAction action, 
                                   int row, int column, const QModelIndex &parent)
{
    qDebug() << "dropMimeData: " << data->formats().join(", ") << " action: " << action;
    return false;
}
 
bool DeviceListModel::insertRows(int row, int count, const QModelIndex &parent)
{
    qDebug() << "insertRows: " << row << " count: " << count;
    if(parent.isValid()) return false;
    return true;
}
 
bool DeviceListModel::removeRows(int row, int count, const QModelIndex &parent)
{
    qDebug() << "removeRows: " << row << " count: " << count;
    if(parent.isValid()) return false;
    return true;
}
 
bool DeviceListModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
    if(!index.isValid()) return false;
    return true;
}
 
void DeviceListModel::setList(const QList<QString> &list)
{
    beginResetModel();
    m_list = list;
    endResetModel();
}
Si je modifie la ligne :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
ui->listView->setDragDropMode(QAbstractItemView::InternalMove);
par
Code : Sélectionner tout - Visualiser dans une fenêtre à part
ui->listView->setDragDropMode(QAbstractItemView::DragDrop);
j'obtiens un icône + et la fonction dropMimeData est bien appelée avec le type d'action "CopyAction". Mais ce n'est pas ce que je veux car il faudrait alors implémenter cette fonction pour que cela fonctionne. Deplus ils s'agit d'une copie et non d'un déplacement. Ou peut être n'ai-je pas bien compris le principe...
D'après ce que j'ai cru comprendre seules le fonctions removeRows(), rowCount(), flags() et supportedDropActions() doivent être réimplémentées pour supporter les "déplacements internes".

Nom : InternalMove_vs_DragDrop.png
Affichages : 161
Taille : 30,5 Ko

A noter que cela fonctionne très bien avec un QListWidget. On peut le tester très facilement depuis Qt Designer. Il suffit de définir l'option dragDropMode à InternalMove.