2016-09-20 70 views
0

我试图通过调用
QQmlProperty::write(gridview, "model", QVariant::fromValue(objlist));从C++设置QML GridViewmodel属性。从C++设置GridView模型属性而不设置上下文

gridview设置是否正确,我可以从C++从QML修改属性,当我把它用6项设置为的QList,并打印出来,我得到
qml: model = item(0x30617b50), Item(0x30617b90), Item(0x30617bd0), Item(0x30617c10), Item(0x30617c50), Item(0x30617cd0),虽然没有显示模型。

Qt文档建议呼吁

QQmlContext *ctxt = view->rootContext(); ctxt->setContextProperty("gridModel", QVariant::fromValue(objlist));

,然后设置从QML属性与model: gridModel,但并没有真正适合我的需要。它工作正常,但只要属性设置正确的数据正在显示。当我从QML打印变量时,输出是
qml: model = [object Object]所以设置上下文属性和设置对象属性之间肯定有区别,但我不知道如何解决这个问题。

+0

如何使用'QQmlProperty :: wr ite'而不是'ctxt-> setContextProperty',或者一般来说如何在不使用全局上下文变量的情况下设置GridView的模型 –

+0

而不是从C++中设置模型,是不是在GridView中定义空模型的选项在C++中,使用QAbstractItemModel的函数更新模型?这将触发相应的信号,允许QML更新GridView。 –

+0

_does_听起来好多了,尤其是当我试图从我的模型中移除项目时,现在遇到了问题。那么我该如何去做呢?我发现很难找到足够的关于C++/QML整合的文档。 –

回答

0

我提出的解决方案与发布的答案略有不同,所以我认为写一个明确的答案是最好的。

的关键是子类QAbstractItemModel(或更精确地..ListModel,所以你不必应对C++ QML行/列)。

在做这种方式,不仅可以简单地将模型作为财产与

QQuickItem *mainform = view->rootObject(); 
QQuickItem *grid = (QQuickItem *)mainform->findChild<QObject*>("GridView object name"); 

ItemModel itemmodel; 
itemmodel.setItems(objlist): 

QQmlProperty::write(grid, "model", QVariant::fromValue(&itemmodel)); 

它还分配时通知QML每当一个变化的模型,例如由一个项目被删除。 (你必须虽然妥善处理的变化,看到removeRows()中的例子)

这里是我的ItemModel:

// itemmodel.h 

#include <QAbstractListModel> 
#include <item.h> 

class ItemModel : public QAbstractListModel 
{ 
    Q_OBJECT 
public: 
    explicit ItemModel(QObject *parent = 0); 
    QHash<int, QByteArray> roleNames() const; 

public slots: 
    void setItems(QList<Item *> items); 
    QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; 
    int rowCount(const QModelIndex & parent = QModelIndex()) const; 
    bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex()); 

private: 
    QList<Item *> items; 
}; 

// itemmodel.cpp 
#include "itemmodel.h" 

ItemModel::ItemModel(QObject *parent) : QAbstractListModel(parent) 
{ 

} 

// Column Names have to match all the Q_PROPERTYs defined in Item 
const char* COLUMN_NAMES[] = { 
    "property1", 
    "property2", 
    "...", 
    NULL 
}; 
QHash<int, QByteArray> makeRoleNames() 
{ 
    int idx = 0; 
    QHash<int, QByteArray> roleNames; 
    while(COLUMN_NAMES[idx]) 
     roleNames[Qt::UserRole + idx + 1] = COLUMN_NAMES[idx++]; 

    return roleNames; 
} 

QHash<int, QByteArray> ItemModel::roleNames() const 
{ 
    static const QHash<int, QByteArray> roleNames = makeRoleNames(); 
    return roleNames; 
} 

void ItemModel::setItems(QList<Item *> items) 
{ 
    this->items = items; 
} 

int ItemModel::rowCount(const QModelIndex & /* parent */) const 
{ 
    return items.count(); 
} 

bool ItemModel::removeRows(int row, int count, const QModelIndex &parent) 
{ 
    Q_UNUSED(parent); 
    beginRemoveRows(QModelIndex(), row, row + count - 1); 
    while (count--) delete items.takeAt(row); 
    // example for custom deletion: 
    //    items.takeAt(row)->removeFromRoot(); 
    endRemoveRows(); 
    return true; 
} 

QVariant ItemModel::data(const QModelIndex &index, int role) const { 
    if (!index.isValid()) 
     return QVariant(); 

    if (index.row() >= items.size() || index.row() < 0) 
     return QVariant(); 

    if (role == Qt::DisplayRole) { 
     return QVariant::fromValue(this->items.at(index.row())); 
    } 

    if (role > Qt::UserRole) 
     return this->items.at(index.row())->property(makeRoleNames()[role]); 
} 

来源:

  • [1] Qt文档页面创建化QAbstractItemModel子类QML
  • [2]化QAbstractItemModel参考
  • [3]化QAbstractItemModel子类指南
  • [4]论坛发帖与QAbstractListModel子
  • [5]工作(几乎data()稍微改变)实现化QAbstractItemModel,从中我把角色名称功能
+0

我建议不要从C++设置QML对象propery,这会使您的C++代码依赖于特定的QML组合。 其余的似乎是处理列表模型的实现,该列表模型与获取QML使用的模型是正交的,并且与手头的问题无关。 –

+0

它与获取修改相关,因为这不是我想要做的首先。正如我的问题所述,我想从C++中设置属性。修改现有的属性可能是一种解决方法,但在对QAbstractItemModels进一步研究之后,我发现他们能够完成我想要做的事情,因此我不必使用解决方法。 –

+0

你的问题是如何设置模型属性,所以你的解决方案处理模型实现的部分正在回答一个不同的问题。 只是想指出,以防其他人读这个问题,并想知道模型班如何演奏它。 您的问题中的代码和您的答案之间的区别是通过'QObject :: setProperty'设置视图的模型,而不是通过属性绑定来设置。 –

0

如果你说QQmlProperty::write正确设置模型,那么你的问题是什么?无论如何,我建议多一个解决方案:

比方说,你有GridView象下面这样:

GridView { 
    anchors.fill: parent 
    objectName: "grid" 
    delegate: Rectangle { 
     id: rect 
     width: 100; 
     height: 100 
     color: Qt.rgba(Math.random(),Math.random(),Math.random(),1) 
     Text { 
      anchors.centerIn: rect 
      text: modelData 
     } 
    } 
} 

objectName是强制性的。

所以在C访问++可能是:

QStringList list; 
list.append("String1"); 
list.append("String2"); 
list.append("String3"); 

QQmlApplicationEngine engine; 
engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); 

QObject *obj = engine.rootObjects()[0]->findChild<QObject *>("grid"); 
if(obj) { 
    obj->setProperty("model",QVariant(list)); 
} 
+0

我需要列表成为对象列表,因为每个GridView元素都有多个属性需要设置。而对于正确设置模型属性,它似乎应该是正确的,当它打印一个项目列表,但它不显示任何东西。GridView似乎期望模型是能够显示它的'[object Object]',但它被设置为'item(0x30617b50),...' –

+0

这不是重写示例使用QObject列表的问题。这是什么意思 - “它打印一个项目列表”?那是什么?你能发布代码吗? – folibis

+0

我把代码放在pastebin上:http://pastebin.com/nPgJT5Xx –

1

试图访问QML从C对象或属性,而不是++我会建议使用在QML端绑定和由C提供的属性值++。

如果通过setContextProperty暴露模型实例并不完全符合您的需求,例如如果模型QML加载时间之后实例化,那么我会建议使用以下方法:

  1. 暴露通过setContextProperty一个QObject派生类的一个实例(),我
  2. 该类得到一个Q_PROPERTY为模型,包括QML的NOTIFY信号
  3. 您绑定该属性的GridView的模型
  4. ,只要你有建立在C++模型或当你需要创建模型的新实例,你散发出上面所说的NOTIFY信号

接口类看起来有点像这个

class MyInterface : public QObject 
{ 
    Q_OBJECT 
    Q_PROPERTY(MyModel* model READ model NOTIFY modelChanged) 

public: 
    MyModel *model() const { return m_model; } 

    void setModel(MyModel *model) { 
     m_model = model; 
     emit modelChanged(); 
    } 

private: 
    MyModel *m_model = 0; 
}; 

当然不是二传手m_model的变化可能是内部MyInterface的,等 这使你完全控制在C++侧时创建模型实例,何时更改,何时删除它。 如果您将类型更改为QAbstractItemModel *或您的一些常见模型基类,甚至可以在运行时更改模型类型(如果您认为合适)

+0

在我看来,这似乎是一种有效的方法。由于之前的上下文实现_kind of_ work,我继续前进并继续制作我的应用程序,但是现在我从视图中删除元素时遇到了问题。当它设置为不可见时,它会留下一个空白,而且从QML我看起来无法访问模型的任何删除方法,那么您的实现是否允许QML从模型中删除项目?如果确实如此,你能否提供任何资料来说明如何做到这一点? –

+0

随着你的建议,我想出了[这](http://stackoverflow.com/a/39654426/2585092)解决方案 –

+0

我不确定你的意思是“你的实现允许QML从模型中删除一个项目? “ 从模型中删除项目与您访问模型的方式正交/无关。模型只需要使用适当的beginRemoveRows()和endRemoveRows()调用来通知有关行删除的视图 –