2016-09-20 111 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()調用來通知有關行刪除的視圖 –