使用cpp模型在拖放QML listView中插入/删除项目

时间:2017-04-21 10:02:08

标签: c++ qt qml qtquick2

我尝试添加QML N Items new Item Items,以添加删除 a {{1}在给定的索引

我做了以下示例,但问题是当我移动一些DataList时,当我尝试插入一个新的时,位置可能不正确并且我没有线索为什么。当我在cpp model中检查new or deleted items时,位置是正确的,但inserted 不会 deleted / new Item正确的位置

似乎当我插入move,然后我delete时出现错误,然后我尝试Item这个insert或{{ 1}}新Item 旁边的Item

这是一个简单的例子(如果需要,你可以运行它)。我拨打了Items DataBlocks

#include "mainwindow.h"
#include <QApplication>
#include <QtQml>
#include <QQuickView>
#include <QQuickWidget>
#include <QQmlApplicationEngine>
int main(int argc, char *argv[])
{

    QApplication a(argc, argv);
    MainWindow w;
    w.show();


    return a.exec();
}

的main.cpp

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include "model.h"

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    void addItem(int index);
    ~MainWindow();

private slots:


private:
    QList<QObject*> dataList;
    Ui::MainWindow *ui;
    BlockModel model;
    int cpt = 0;
};

#endif // MAINWINDOW_H

mainwindow.h

#include <QtQml>
#include <QQuickView>
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "QQuickWidget"
#include <QStringList>


MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{

     int nbItems = 5;

     for(; cpt < nbItems; cpt ++) {
         Block a = Block(QString("Item ")+QString::number(cpt));
         model.addBlock(a);
     }

    ui->setupUi(this);

    QQuickWidget *view = new QQuickWidget;
    QQmlContext *ctxt = view->rootContext();

    ctxt->setContextProperty("myModel", &model);
    view->setSource(QUrl::fromLocalFile("main.qml"));
    view->setGeometry(0, 200, 600, 400);
    view->setResizeMode(QQuickWidget::SizeRootObjectToView);
    ui->dockWidget_3->setWidget(view);
}

MainWindow::~MainWindow()
{
    delete ui;
}

mainwindow.cpp

#include <QAbstractListModel>
#include <QStringList>
#include <qqmlcontext.h>
#include <QDebug>
#include <QStringList>

//![0]
class Block
{
public:
    Block(){
    }

    Block(const QString &name);

    QString nameBlock() const;

    void setName(QString n) {
        m_name = n;
    }

private:
    QString m_name;
};

class BlockModel : public QAbstractListModel
{
    Q_OBJECT
public:

    Block* getBlock(QString name);

    Q_INVOKABLE void moveBlock(int from,int to);
    Q_INVOKABLE void insertBlock(int index);
    Q_INVOKABLE void deleteBlock(int index);

    enum BlockRoles {
        nameRole = Qt::UserRole + 1,
    };

    BlockModel(QObject *parent = 0);

    void setContext(QQmlContext *ctx) {
        m_ctx = ctx;
    }

    void setName(const QString &name);

    void addBlock(const Block &Block);

    int rowCount(const QModelIndex & parent = QModelIndex()) const;

    QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const;
    QHash<int, QByteArray> roleNames() const;

private:
    QList<Block> m_blocks;
    QQmlContext*  m_ctx;
    int cpt = 0;
};

mode.h

#include "model.h"
#include "qDebug"
Block::Block(const QString &name)
    : m_name(name)
{
}



QString Block::nameBlock() const
{
    return m_name;
}


BlockModel::BlockModel(QObject *parent)
    : QAbstractListModel(parent)
{
}

void BlockModel::addBlock(const Block &Block)
{
    beginInsertRows(QModelIndex(), rowCount(), rowCount());
    m_blocks << Block;
    endInsertRows();
}



int BlockModel::rowCount(const QModelIndex & parent) const {
    Q_UNUSED(parent);
    return m_blocks.count();
}

void BlockModel::moveBlock(int from, int to) {
     m_blocks.move(from,to);
}

void BlockModel::insertBlock(int index) {
    Block b =(Block(QString("New Item ")+QString::number(cpt)));
    beginInsertRows(QModelIndex(),index+1,index+1);
    m_blocks.insert(index+1,b);
    endInsertRows();
    cpt++;
}

void BlockModel::deleteBlock(int index) {
    beginRemoveRows(QModelIndex(),index,index);
    m_blocks.removeAt(index);
    endRemoveRows();
}

QVariant BlockModel::data(const QModelIndex & index, int role) const {
    if (index.row() < 0 || index.row() >= m_blocks.count())
        return QVariant();

    const Block &Block = m_blocks[index.row()];
    if (role == nameRole)
        return Block.nameBlock();

    return QVariant();
}

//![0]
QHash<int, QByteArray> BlockModel::roleNames() const {
    QHash<int, QByteArray> roles;

    roles[nameRole] = "nameBlock";

    return roles;
}

model.cpp

import QtQuick 2.7
import QtQuick.Controls 1.4
import QtQuick.Window 2.2
import QtQuick.Dialogs 1.2
import QtQuick.Layouts 1.2
import QtQml.Models 2.2
import QtQuick.Controls.Styles 1.4

Rectangle {
    id : rootRectangle
    visible: true
    ScrollView {
        anchors.fill:parent
        ListView{
            id: root
            width: parent.width; height: parent.height
            property int visualIndex: -1

            displaced: Transition {
                NumberAnimation { properties: "y"; easing.type: Easing.OutQuad }
            }

            model: DelegateModel {

                id: visualModel
                model: myModel
                delegate: Component {
                    MouseArea {

                        id: delegateRoot

                        property int visualIndex: DelegateModel.itemsIndex
                        cursorShape: Qt.PointingHandCursor
                        width: root.width; height: 100

                        drag.target:  icon
                        drag.axis: Drag.YAxis

                        Behavior on height {
                            PropertyAnimation { duration: 100 }
                        }

                        Rectangle {
                            anchors.top:  delegateRoot.top
                            anchors.left: delegateRoot.left
                            id: icon
                            objectName: nameBlock
                            width: root.width-5; height: 100
                            color:  "skyblue"

                            radius: 3
                            Text {
                                objectName: "rect"
                                id: title
                                anchors.fill: parent
                                anchors.margins: 10
                                horizontalAlignment: Text.AlignLeft
                                verticalAlignment: Text.AlignVCenter
                                text: nameBlock
                            }

                            Drag.active: delegateRoot.drag.active
                            Drag.source: delegateRoot
                            Drag.hotSpot.x: 36
                            Drag.hotSpot.y: 36

                                Button {
                                    id : buttonAdd
                                    text: "Add Block"

                                    anchors{
                                        right: parent.right
                                        top: parent.top
                                        bottom: parent.bottom
                                        margins: 30
                                    }


                                    onClicked: {
                                        myModel.insertBlock(visualIndex)
                                    }
                                }

                                Button {
                                    id : buttonDelete
                                    text: "Delete Block"
                                    anchors{
                                        right: buttonAdd.left
                                        top: parent.top
                                        bottom: parent.bottom
                                        margins: 30
                                    }
                                    onClicked: {
                                        myModel.deleteBlock(visualIndex)
                                    }
                                }


                            states: [
                                State {
                                    when: icon.Drag.active
                                    ParentChange {
                                        target: icon
                                        parent: root
                                    }
                                    AnchorChanges {
                                        target: icon;
                                        anchors.horizontalCenter: undefined;
                                        anchors.verticalCenter: undefined
                                    }
                                }
                            ]

                            transitions: Transition {
                                // Make the state changes smooth
                                ParallelAnimation {
                                    ColorAnimation { property: "color"; duration: 500 }
                                    NumberAnimation { duration: 300; properties: "detailsOpacity,x,contentY,height,width,font.pixelSize,font.bold,visible" }
                                }
                            }
                        }

                        DropArea {
                            anchors { fill: parent; margins: 15 }
                            onEntered: {
                                visualModel.items.move(drag.source.visualIndex, delegateRoot.visualIndex)
                                myModel.moveBlock(drag.source.visualIndex,delegateRoot.visualInde)
                            }
                        }
                    }
                }
            }
        }
    }
}

main.qml

你知道我做错了什么吗? 非常感谢,祝你有个美好的一天!

1 个答案:

答案 0 :(得分:1)

移动物品时有两个错误。在DropArea.onEntered中,如果您在drag.source.visualIndex之前和之后打印delegateRoot.visualIndexvisualModel.items.move,则会在移动后看到值已被修改。这意味着您在调用myModel.moveBlock时移动了错误的行。要解决此问题,请在移动项目之前保存该值:

DropArea {
    anchors { fill: parent; margins: 15 }
    onEntered: {
        var from = drag.source.visualIndex;
        var to = delegateRoot.visualIndex;
        visualModel.items.move(from, to);
        myModel.moveBlock(from, to);
    }
}

在C ++模型中移动项目时,应该像插入/移除项目一样调用QAbstractItemModel::beginMoveRows。否则,QML DelegateModel无法正确显示您的模型。请记住,在实施BlockModel::moveBlock时,模型的目标行与源列表m_blocks的目标行不同。有关详细信息,请参阅QAbstractItemModel::beginMoveRows documentation中的最后一个示例。

void BlockModel::moveBlock(int from, int to) {
    if (from == to)
        return;
    auto modelFrom = from;
    auto modelTo = to + (from < to ? 1 : 0);

    beginMoveRows(QModelIndex(), modelFrom, modelFrom, QModelIndex(), modelTo);
    m_blocks.move(from,to);
    endMoveRows();
}