2017-04-21 85 views
0

我試圖在N Items方式QML添加到ListView添加在給定的指數刪除一個new Item插入/刪除項目的拖放QML的ListView與CPP模型

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

看來,當我插入一個new Item出現錯誤,那麼我move它,然後我嘗試delete這個IteminsertItem旁邊這個新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

移動物品時有兩個錯誤。在DropArea.onEntered中,如果您在visualModel.items.move之前和之後打印出drag.source.visualIndexdelegateRoot.visualIndex,則會看到移動後值被修改。這意味着您在致電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(); 
} 
+1

你好,非常感謝你的回覆,它工作正常!但是,我意識到如果在cpp中使用'moveRows',則不需要使用'visualModel.items.move(from,to);'。否則你的解決方案是完美的 –