如何在QML ListView和Grid之间共享模型的项目

时间:2016-04-22 11:11:10

标签: qt view qml

我想知道在QML中实现以下功能的最佳方法:

我的 ListView 包含可放置元素,网格初始化为 DropArea 。 ListView使用从 QAbstractItemModel 派生的模型。我想在网格上放一个元素并与之交互(例如重命名)。目前,ListView中的任何修改都会更新模型,但网格中元素的修改如何更新模型?

网格中可能有多个项目与ListView模型的子集相对应。我不知道如何实现这一目标。无法使用,因为网格不是GridView,必须在特定位置移动/设置项目。所以我试着:

  • 创建一个显示在已删除项目上的ListView,使用与用于拖动项目的源ListView相同的模型,
  • 设置相同的rootIndex,然后设置相同的索引

我接近解决方案,但我认为这不是最好的方法。

有任何线索吗?

由于

2 个答案:

答案 0 :(得分:0)

  

我想对同一模型有不同的视觉表现   ListView中的项目和Grid中的组件。所以,修改了   ListView中的项应该更新网格中的项目   反之亦然。

如果您的模型数据不是QObject导出的NOTIFY和属性,则只能通过模型​​进行更改通知。

由于您不会将该模型用于网格,这意味着您的模型必须使用基础QObject实例。 A generic model object可能派上用场。

如果有,只需要引用基础QObject模型项并使用绑定来设置列表视图委托。然后,当您拖放时,您只需要将对QObject的引用传递给您将在网格中创建的其他可视化表示。

最后,当您从模型中删除项目时,请注意不要留下悬空引用,因为这很可能会使您的应用程序崩溃。当模型项目对象被销毁时,使用onDestruction附加信号清除网格中的元素。

答案 1 :(得分:0)

我终于找到了一个解决方案,创建了一个C ++类型,它继承自QObject,可以嵌入到QML对象中。此类型具有读/写属性,并使用与ListView相同的模型进行初始化。有趣的方法是:

/* writing to a property **from QML** goes here */
void ModelItem::setName(const QString& name)
{
    setModelData(GroupMemberModel::Nom, name);
}
/* then here */
bool ModelItem::setModelData(GroupMemberModel::Role role, const QVariant& value)
{
    return m_model->setData(m_modelIndex, value, role);
}

/* any changes in the model fall here (signals/slots mecanism)*/
void ModelItem::dataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight, const QVector<int>& roles)
{
    if(m_modelIndex.row() < topLeft.row() || m_modelIndex.row() > bottomRight.row())
        return;
    if(m_modelIndex.column() < topLeft.column() || m_modelIndex.column() > bottomRight.column())
        return;
    //Index is modified, emit signal
    foreach(int role, roles) {
        emitDataChanged(role);
    }
}
/* **notify QML** by emit signal on property */
void ModelItem::emitDataChanged(int role) const
{
    if(role < (Qt::UserRole+1))
        role+=Qt::UserRole+1;

    switch(role)
    {
    case GroupMemberModel::Nom:
        emit nameChanged();
        break;
    default:
        qDebug() << "ModelItem::dataChanged, unknown role";
        break;
    }
}

这可以根据需要运行,并且比我想象的更简单。