簡體   English   中英

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

[英]Inserting/Deleting Items in a drag&drop QML listView with cpp model

我嘗試在N ItemsQML中向ListView添加一種在給定索引添加刪除new Item方法

我做了下面的例子,但問題是當我移動一些Items ,當我嘗試插入一個新的時,位置可能不正確,我不知道為什么。 當我在我的cpp model檢查我的DataList時,位置是正確的,但是,不會正確的位置inserted / deleted new or deleted items

當我插入一個new Item ,然后move它,然后我嘗試deleteItem或在此新Item旁邊insert一個Item,似乎會發生錯誤

這是一個簡單的示例(如果需要,可以運行它)。 我稱我的Items Data : Blocks

#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();
}

主程序

#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

主窗口.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;
}

主窗口.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;
};

模式.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;
}

模型.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)
                            }
                        }
                    }
                }
            }
        }
    }
}

主文件

你知道我做錯了什么嗎? 非常感謝,祝你有美好的一天!

移動物品時有兩個錯誤。 DropArea.onEntered ,如果你打印出兩個drag.source.visualIndexdelegateRoot.visualIndex前后visualModel.items.move ,你會看到,價值觀正在修改后。 這意味着您在調用myModel.moveBlock時移動了錯誤的行。 要解決此問題,請在移動項目之前保存該值:

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

在 C++ 模型中移動項目時,應該像插入/刪除項目一樣調用QAbstractItemModel::beginMoveRows 否則 QML DelegateModel無法正確顯示您的模型。 請記住,在實現BlockModel::moveBlock ,模型的目標行與源列表m_blocks的目標行不同。 有關詳細信息,請參閱QAbstractItemModel::beginMoveRows文檔中的最后一個示例。

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();
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM