Page 1 of 2 12 LastLast
Results 1 to 20 of 24

Thread: QML ListModel for interaction with C++

  1. #1
    Join Date
    Nov 2011
    Posts
    26
    Thanks
    6
    Thanked 3 Times in 3 Posts
    Qt products
    Qt3 Qt4 Qt/Embedded Qt Jambi
    Platforms
    Unix/X11 Windows

    Default QML ListModel for interaction with C++

    Hey Guys,

    I am already struggling with this problem for about 3 days... seems I am kinda stuck now =/.
    What I want: I want a QList<T> to interact with my QML view - dynamically - so if I remove an item via a C++ interface call to the model the item should disappear in the QML view

    What I know so far: I recognized (logical anyways) that the QList i had before:
    Qt Code:
    1. //Q_PROPERTY(QDeclarativeListProperty<TaskData> taskData READ taskData CONSTANT)
    2. //QDeclarativeListProperty<TaskData> taskData();
    To copy to clipboard, switch view to plain text mode 
    wasn't working because it provides no notification for the view -> after some research I decided to implement my own ListModel then...

    The Model seems to work but the View does not display anything...

    QMLPtrNotificationModel.h looks like shown below:
    Qt Code:
    1. class QMLPtrAbstractItem : public QDeclarativeItem
    2. {
    3. public:
    4. QMLPtrAbstractItem(QDeclarativeItem *parent = 0);
    5. virtual ~QMLPtrAbstractItem() { }
    6.  
    7. virtual QString getName() const = 0;
    8. virtual QString setName() const = 0;
    9. };
    10.  
    11. class QMLPtrNotificationModel : public QAbstractListModel
    12. {
    13. Q_OBJECT
    14.  
    15. public:
    16. explicit QMLPtrNotificationModel(QObject *parent = 0);
    17. QMLPtrNotificationModel(const QList<QMLPtrAbstractItem*> &list, QObject *parent = 0);
    18. ~QMLPtrNotificationModel();
    19.  
    20. int rowCount(const QModelIndex &parent = QModelIndex()) const;
    21. int count() const { return rowCount(QModelIndex()); }
    22.  
    23. QVariant data(const QModelIndex &index, int role) const;
    24. bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole);
    25.  
    26. Qt::ItemFlags flags(const QModelIndex &index) const;
    27.  
    28. bool insertRows(int row, int count, const QModelIndex &parent = QModelIndex());
    29. bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex());
    30.  
    31. void sort(int column, Qt::SortOrder order = Qt::AscendingOrder);
    32.  
    33. QList<QMLPtrAbstractItem*> operator()();
    34. const QList<QMLPtrAbstractItem*> operator()();
    35.  
    36. QList<QMLPtrAbstractItem*> getList() const;
    37. void setList(const QList<QMLPtrAbstractItem*> &list);
    38.  
    39. QMLPtrAbstractItem* at(int index);
    40.  
    41. bool addElement(QMLPtrAbstractItem *element);
    42. bool removeElement(QMLPtrAbstractItem *element);
    43. bool clear();
    44.  
    45. Qt::DropActions supportedDropActions() const;
    46.  
    47. private Q_SLOTS:
    48. void refresh();
    49.  
    50. private:
    51. Q_DISABLE_COPY(QMLPtrNotificationModel)
    52. QList<QMLPtrAbstractItem*> lst;
    53. };
    54.  
    55. QML_DECLARE_TYPE(QMLPtrNotificationModel)
    To copy to clipboard, switch view to plain text mode 


    The QMLPtrNotificationModel.cpp looks like shown below (not all functions provided - I think that not all are necessary to document the problem)
    Qt Code:
    1. QMLPtrAbstractItem::QMLPtrAbstractItem(QDeclarativeItem *parent)
    2. : QDeclarativeItem(parent)
    3. {
    4. }
    5.  
    6. QMLPtrNotificationModel::QMLPtrNotificationModel(QObject *parent)
    7. {
    8. }
    9.  
    10. QMLPtrNotificationModel::QMLPtrNotificationModel(const QList<QMLPtrAbstractItem*> &list, QObject *parent)
    11. : QAbstractListModel(parent), lst(list)
    12. {
    13. }
    14.  
    15. QMLPtrNotificationModel::~QMLPtrNotificationModel()
    16. {
    17. clear();
    18. }
    19.  
    20. int QMLPtrNotificationModel::rowCount(const QModelIndex &parent) const
    21. {
    22. if (parent.isValid())
    23. return 0;
    24.  
    25. return lst.count();
    26. }
    27.  
    28. QVariant QMLPtrNotificationModel::data(const QModelIndex &index, int role) const
    29. {
    30. if (index.row() < 0 || index.row() >= lst.size())
    31. return QVariant();
    32.  
    33. if (role == Qt::DisplayRole || role == Qt::EditRole)
    34. return lst.at(index.row())->getName();
    35.  
    36. return QVariant();
    37. }
    38.  
    39. Qt::ItemFlags QMLPtrNotificationModel::flags(const QModelIndex &index) const
    40. {
    41. if (!index.isValid())
    42. return QAbstractItemModel::flags(index) | Qt::ItemIsDropEnabled;
    43.  
    44. return QAbstractItemModel::flags(index) | Qt::ItemIsEditable | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled;
    45. }
    46.  
    47. bool QMLPtrNotificationModel::setData(const QModelIndex &index, const QVariant &value, int role)
    48. {
    49. if (index.row() >= 0 && index.row() < lst.size()
    50. && (role == Qt::EditRole || role == Qt::DisplayRole)) {
    51.  
    52. lst.at(index.row())->setName(value.toString());
    53. emit dataChanged(index, index);
    54. return true;
    55. }
    56. return false;
    57. }
    58.  
    59. bool QMLPtrNotificationModel::insertRows(int row, int count, const QModelIndex &parent)
    60. {
    61. if (count < 1 || row < 0 || row > rowCount(parent))
    62. return false;
    63.  
    64. beginInsertRows(QModelIndex(), row, row + count - 1);
    65.  
    66. for (int r = 0; r < count; ++r){
    67. lst.insert(row, NULL);
    68. }
    69.  
    70. endInsertRows();
    71.  
    72. return true;
    73. }
    74.  
    75. bool QMLPtrNotificationModel::removeRows(int row, int count, const QModelIndex &parent)
    76. {
    77. if (count <= 0 || row < 0 || (row + count) > rowCount(parent))
    78. return false;
    79.  
    80. beginRemoveRows(QModelIndex(), row, row + count - 1);
    81.  
    82. for (int r = 0; r < count; ++r){
    83. delete lst.at(row);
    84. lst.removeAt(row);
    85. }
    86.  
    87. endRemoveRows();
    88.  
    89. return true;
    90. }
    91.  
    92. bool QMLPtrNotificationModel::clear()
    93. {
    94. return removeRows(0, rowCount(), QModelIndex());
    95. }
    96.  
    97. bool QMLPtrNotificationModel::addElement(QMLPtrAbstractItem *element)
    98. {
    99. int position = rowCount();
    100. if(insertRows(position, 1, QModelIndex())){
    101. lst << element;
    102. return true;
    103. }
    104. return false;
    105. }
    106.  
    107. bool QMLPtrNotificationModel::removeElement(QMLPtrAbstractItem *element)
    108. {
    109. int position = lst.indexOf(element);
    110. if(removeRows(position, 1, QModelIndex())){
    111. return true;
    112. }
    113. return false;
    114. }
    115.  
    116. QMLPtrAbstractItem* QMLPtrNotificationModel::at(int index)
    117. {
    118. return lst.at(index);
    119. }
    To copy to clipboard, switch view to plain text mode 

    It seems QML doesn't recognize anthing - the structure looks as follows:
    Qt Code:
    1. import QtQuick 1.1
    2. import QMLPtrNotificationModel 1.0
    3.  
    4. Item {
    5. property variant orientation: Qt.Vertical
    6.  
    7. ListView {
    8. id: completeTable
    9.  
    10. QMLPtrNotificationModel {
    11. id: myListmodel
    12. }
    13.  
    14. model: myListmodel
    15. delegate: TaskData { }
    16. }
    To copy to clipboard, switch view to plain text mode 

    And i registered QMLPtrNotificationModel as QML Type via C++ like that:
    Qt Code:
    1. qmlRegisterType<QMLPtrNotificationModel>("QMLPtrNotificationModel", 1, 0, "QMLPtrNotificationModel");
    To copy to clipboard, switch view to plain text mode 

    I know it's a big part of code for a single post - but I think the error is in both parts, QML and the Model itself.. looks like missing notifications again?
    Would be really lovely if anybody of you has an idea to fix this issue -> my QML view is empty at the moment (I added elements via addElement())
    The Elements to add are correctly derived from QMLPtrAbstractItem and implement the abstract methods.

    Any ideas?

  2. #2
    Join Date
    Nov 2011
    Posts
    26
    Thanks
    6
    Thanked 3 Times in 3 Posts
    Qt products
    Qt3 Qt4 Qt/Embedded Qt Jambi
    Platforms
    Unix/X11 Windows

    Default Re: QML ListModel for interaction with C++

    Nobody any idea!?

  3. #3
    Join Date
    Nov 2010
    Posts
    82
    Thanked 9 Times in 9 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: QML ListModel for interaction with C++

    is your listview really empty or field with empty items ?
    can you give us the delegate ?
    did you try to add emit datachanged(QModelIndex(), QModelIndex()); to refresh your model (it s not supposed to be needed but...)

  4. #4
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: QML ListModel for interaction with C++

    I think your addElement and removeElement implementations are incorrect. Try an equivalent of:
    Qt Code:
    1. bool QMLPtrNotificationModel::addElement(QMLPtrAbstractItem *element)
    2. {
    3. int position = rowCount();
    4. beginInsertRows(QModelIndex(), position, position);
    5. lst << element;
    6. endInsertRows();
    7. return true;
    8. }
    To copy to clipboard, switch view to plain text mode 
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


  5. The following user says thank you to wysota for this useful post:

    shock (16th March 2012)

  6. #5
    Join Date
    Nov 2011
    Posts
    26
    Thanks
    6
    Thanked 3 Times in 3 Posts
    Qt products
    Qt3 Qt4 Qt/Embedded Qt Jambi
    Platforms
    Unix/X11 Windows

    Default Re: QML ListModel for interaction with C++

    Before i used an implementation with:
    Qt Code:
    1. Q_PROPERTY(QDeclarativeListProperty<TaskData> taskData READ taskData CONSTANT)
    2. QDeclarativeListProperty<TaskData> taskData();
    To copy to clipboard, switch view to plain text mode 

    That worked so far ... but if i delete an item via C++ QML gets not notified because it's just a QList...
    It looked like that (and now should look the same way with the model.. but i think my implementation with the model went wrong in the very beginning .. possibly ListModel is not what i need !?):
    ItShouldLookLikeThatAgain.jpg

    The implementation in QML before looked like that (i am afraid - i used a Repeater { } before -- don't know if there is really a difference)
    Qt Code:
    1. Item {
    2. //width: 900; height: 800
    3. property variant scrollArea
    4. property variant orientation: Qt.Vertical
    5.  
    6. ListView {
    7. id: completeTable
    8. Rectangle {
    9. id: cornerWidget
    10. width: dataHandler.getEmpWidth()
    11. height: dataHandler.getColumnHeight()
    12. anchors.top: parent.top
    13. anchors.left: parent.left
    14. gradient: Gradient {....}
    15. border.color: "black"
    16. border.width: 2
    17. radius: 1
    18.  
    19. Text {...}
    20. }
    21. Grid {
    22. anchors.top: cornerWidget.bottom
    23. anchors.left: parent.left
    24. columns: 1
    25.  
    26. Repeater {
    27. id: empGrid
    28. model: employees
    29. delegate: Employee {}
    30. }
    31. }
    32.  
    33. Grid {
    34. anchors.left: cornerWidget.right
    35. columns: dataHandler.getColumnCount()
    36.  
    37. Repeater {
    38. id: dayHeaderGrid
    39. model: dateHeaderData
    40. delegate: DateHeaderData {}
    41. }
    42. }
    43. Grid {
    44. anchors.left: cornerWidget.right
    45. anchors.top: cornerWidget.bottom
    46. columns: dataHandler.getColumnCount()
    47.  
    48. Repeater {
    49. id: calendarGrid
    50. model: calendarData
    51. delegate: CalendarData { border.width: 2; opacity: 1; visible: true}
    52. }
    53. }
    54. }
    55.  
    56. Repeater {
    57. id: tasks
    58. model: taskData
    59. delegate: TaskData {}
    60. }
    61. }
    To copy to clipboard, switch view to plain text mode 

    In this case taskData was the list .. this worked for the view .. but not for the add/delete
    (I can provide the delegate too if it's needed but it seems i have an error somewhere with the model and it's instance in the Item/ListView)

    No it looks like that:
    emptyQMLView.jpg

    seems empty for me (if i compare them ... the list in the model is filled .. i checked that)
    The QML Code now looks like that:
    Qt Code:
    1. Item {
    2. //width: 900; height: 800
    3. property variant scrollArea
    4. property variant orientation: Qt.Vertical
    5.  
    6. ListView {
    7. id: completeTable
    8.  
    9. QMLPtrNotificationModel {
    10. id: myListmodel
    11. }
    12.  
    13. Rectangle {
    14. id: cornerWidget
    15. width: dataHandler.getEmpWidth()
    16. height: dataHandler.getColumnHeight()
    17. anchors.top: parent.top
    18. anchors.left: parent.left
    19. gradient: Gradient {....}
    20. border.color: "black"
    21. border.width: 2
    22. radius: 1
    23.  
    24. Text {
    25. .....
    26. }
    27. }
    28. Grid {
    29. anchors.top: cornerWidget.bottom
    30. anchors.left: parent.left
    31. columns: 1
    32.  
    33. Repeater {
    34. id: empGrid
    35. model: employees
    36. delegate: Employee {}
    37. }
    38. }
    39.  
    40. Grid {
    41. anchors.left: cornerWidget.right
    42. columns: dataHandler.getColumnCount()
    43.  
    44. Repeater {
    45. id: dayHeaderGrid
    46. model: dateHeaderData
    47. delegate: DateHeaderData {}
    48. }
    49. }
    50. Grid {
    51. anchors.left: cornerWidget.right
    52. anchors.top: cornerWidget.bottom
    53. columns: dataHandler.getColumnCount()
    54.  
    55. Repeater {
    56. id: calendarGrid
    57. model: calendarData
    58. delegate: CalendarData { border.width: 2; opacity: 1; visible: true}
    59. }
    60. }
    61.  
    62. model: myListmodel
    63. delegate: TaskData { }
    64. }
    65.  
    66. //Repeater {
    67. // id: tasks
    68. // model: myListmodel
    69. // delegate: TaskData { }
    70. //}
    71. }
    To copy to clipboard, switch view to plain text mode 

    As you can see, i also tried the repeater again - gave the same meaninless empty result =/
    I don't really know where to start debugging and where to look for the error in the QML <-> C++ communication -> complicated as it seems

    @wysota: Thanks for your tip! I changed the implementation of my derived ListModel to the following:
    Qt Code:
    1. QMLPtrAbstractItem::QMLPtrAbstractItem(QDeclarativeItem *parent)
    2. : QDeclarativeItem(parent)
    3. {
    4. }
    5.  
    6. QMLPtrNotificationModel::QMLPtrNotificationModel(QObject *parent)
    7. {
    8. }
    9.  
    10. QMLPtrNotificationModel::QMLPtrNotificationModel(const QList<QMLPtrAbstractItem*> &list, QObject *parent)
    11. : QAbstractListModel(parent), lst(list)
    12. {
    13. }
    14.  
    15. QMLPtrNotificationModel::~QMLPtrNotificationModel()
    16. {
    17. clear();
    18. }
    19.  
    20. int QMLPtrNotificationModel::rowCount(const QModelIndex &parent) const
    21. {
    22. if (parent.isValid())
    23. return 0;
    24.  
    25. return lst.count();
    26. }
    27.  
    28. QVariant QMLPtrNotificationModel::data(const QModelIndex &index, int role) const
    29. {
    30. if (index.row() < 0 || index.row() >= lst.size())
    31. return QVariant();
    32.  
    33. if (role == Qt::DisplayRole || role == Qt::EditRole)
    34. return lst.at(index.row())->getName();
    35.  
    36. return QVariant();
    37. }
    38.  
    39. Qt::ItemFlags QMLPtrNotificationModel::flags(const QModelIndex &index) const
    40. {
    41. if (!index.isValid())
    42. return QAbstractItemModel::flags(index) | Qt::ItemIsDropEnabled;
    43.  
    44. return QAbstractItemModel::flags(index) | Qt::ItemIsEditable | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled;
    45. }
    46.  
    47. bool QMLPtrNotificationModel::setData(const QModelIndex &index, const QVariant &value, int role)
    48. {
    49. if (index.row() >= 0 && index.row() < lst.size()
    50. && (role == Qt::EditRole || role == Qt::DisplayRole)) {
    51.  
    52. if(role == Qt::EditRole)
    53. qDebug() << "QMLPtrNotificationModel::setData(role == Qt::EditRole)";
    54. else
    55. qDebug() << "QMLPtrNotificationModel::setData(role == Qt::DisplayRole)";
    56.  
    57. lst.at(index.row())->setName(value.toString());
    58. emit dataChanged(index, index);
    59. return true;
    60. }
    61.  
    62. return false;
    63. }
    64.  
    65. QList<QMLPtrAbstractItem*> QMLPtrNotificationModel::getList() const
    66. {
    67. return lst;
    68. }
    69.  
    70. void QMLPtrNotificationModel::setList(const QList<QMLPtrAbstractItem*> &myitems)
    71. {
    72. emit beginResetModel();
    73. lst = myitems;
    74. emit endResetModel();
    75. emit countChanged();
    76. }
    77.  
    78. Qt::DropActions QMLPtrNotificationModel::supportedDropActions() const
    79. {
    80. return QAbstractItemModel::supportedDropActions() | Qt::MoveAction;
    81. }
    82.  
    83. bool QMLPtrNotificationModel::clear()
    84. {
    85. qDebug() << "QMLPtrNotificationModel::clear() == false";
    86. return false;
    87. }
    88.  
    89.  
    90. QList<QMLPtrAbstractItem*>* QMLPtrNotificationModel::operator()()
    91. {
    92. return &lst;
    93. }
    94.  
    95. bool QMLPtrNotificationModel::addElement(QMLPtrAbstractItem *element)
    96. {
    97. int position = rowCount();
    98. beginInsertRows(QModelIndex(), position, position);
    99. lst << element;
    100. qDebug() << "Added Element - new count(): " << lst.count();
    101. endInsertRows();
    102. return true;
    103. }
    104.  
    105. bool QMLPtrNotificationModel::removeElement(QMLPtrAbstractItem *element)
    106. {
    107. int position = lst.indexOf(element);
    108. beginRemoveRows(QModelIndex(), position, position);
    109.  
    110. delete lst.at(position);
    111. lst.removeAt(position);
    112.  
    113. endInsertRows();
    114. return true;
    115. }
    116.  
    117. QMLPtrAbstractItem* QMLPtrNotificationModel::at(int index)
    118. {
    119. return lst.at(index);
    120. }
    121.  
    122. void QMLPtrNotificationModel::refresh()
    123. {
    124. QList<QMLPtrAbstractItem*> myList = getList();
    125. setList(myList);
    126. }
    To copy to clipboard, switch view to plain text mode 

    Please - forget the meaningless clear(); function for the moment - i don't think that this might be the problem -> let's talk about clear and delete if i am able to fill the fucking view again ^^

    Here is the class description of the QMLPtrAbstractItem again and the definition of the QMLPtrNotificationModel (QMLPtrNotificationModel.h):
    Qt Code:
    1. class QMLPtrAbstractItem : public QDeclarativeItem
    2. {
    3. public:
    4. QMLPtrAbstractItem(QDeclarativeItem *parent = 0);
    5. virtual ~QMLPtrAbstractItem() { }
    6.  
    7. virtual QString getName() const = 0;
    8. virtual void setName(QString name) = 0;
    9. };
    10.  
    11. class QMLPtrNotificationModel : public QAbstractListModel
    12. {
    13. Q_OBJECT
    14. .......
    15. };
    16.  
    17. QML_DECLARE_TYPE(QMLPtrNotificationModel)
    To copy to clipboard, switch view to plain text mode 

    I hope you any further ideas for me - i am stuck ... =(
    Thanks, greets

  7. #6
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: QML ListModel for interaction with C++

    To test your QML implementation I suggest you attach a QStandardItemModel to it and try to add and remove items in it from within C++ to see if changes are properly reflected in QtQuick view.
    Attached Files Attached Files
    Last edited by wysota; 13th March 2012 at 09:10.
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


  8. The following user says thank you to wysota for this useful post:

    shock (16th March 2012)

  9. #7
    Join Date
    Nov 2011
    Posts
    26
    Thanks
    6
    Thanked 3 Times in 3 Posts
    Qt products
    Qt3 Qt4 Qt/Embedded Qt Jambi
    Platforms
    Unix/X11 Windows

    Default Re: QML ListModel for interaction with C++

    Thanks for that example wysota - seems very helpful! The problem is that the classes are derived from QDeclarativeItem and i can't really change stuff to QStandardItem because it's column/row based and the things are working with normal X/Y coordinates .. seems a bit more complicated (inheritance from QStandardItem and QDeclarativeItem seems not really pretty - and not working anyways .. i did it to test stuff -> i get an empty table again like the one i already posted)

    I think what i need is something like QStandardDeclarativeItem or QDeclarativeItemModel ? Which is a DeclarativeItem derived from QStandardItem or from QAbstractItem which means i have to reimplement the whole stuff!? =/

    Possibly i am wrong!? .. hopefully...
    Last edited by shock; 14th March 2012 at 15:00.

  10. #8
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: QML ListModel for interaction with C++

    QDeclarativeItem is something you show in QtQuick. The model has nothing to do with this. It won't make any sense to keep a list of QDeclarativeItem instances in C++ and expect that to be somehow automatically trasfered to QtQuick. Your deleage needs to be a component and for that you can use your declarative item but the model is intended to hold data.
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


  11. The following user says thank you to wysota for this useful post:

    shock (16th March 2012)

  12. #9
    Join Date
    Nov 2011
    Posts
    26
    Thanks
    6
    Thanked 3 Times in 3 Posts
    Qt products
    Qt3 Qt4 Qt/Embedded Qt Jambi
    Platforms
    Unix/X11 Windows

    Default Re: QML ListModel for interaction with C++

    Ahm ... yes .. sure - you are right, it seems i missed that point while writing absurd code ...
    After all - with the right code - it does not seem so difficult at all So however here is my solution:

    Derive a model from QAbstractListModel and use specific roles for each function related to the Object/Delegate that should be displayed via QML (which is accessing these roles)
    ListView QML:
    Qt Code:
    1. import QtQuick 1.1
    2.  
    3. Item {
    4. ListView {
    5. ...
    6. ...
    7. }
    8. Repeater {
    9. id: tasks
    10. model: myMod //the model must be "registered" via the Context:ui->declarativeView->rootContext()->setContextProperty("myMod", model);
    11. delegate: TaskData { }
    12. }
    13. }
    To copy to clipboard, switch view to plain text mode 

    Delegate QML:
    Qt Code:
    1. Rectangle {
    2. Text {
    3. id: taskName
    4. anchors.centerIn: parent
    5. text: name; color: "white";
    6. }
    7. }
    To copy to clipboard, switch view to plain text mode 

    C++ Class (Element)
    Qt Code:
    1. class Element: public QDeclarativeItem
    2. {
    3. Q_OBJECT
    4. public:
    5. Element() { }
    6. virtual ~Element() { }
    7.  
    8. virtual QString getName() const { return _name; }
    9. virtual void setName(QString name) { _name = name; }
    10.  
    11. private:
    12. QString _name;
    13. };
    To copy to clipboard, switch view to plain text mode 

    C++ Derived Model (header):
    Qt Code:
    1. class QMLPtrNotificationModel : public QAbstractListModel
    2. {
    3. Q_OBJECT
    4.  
    5. public:
    6. enum roles {
    7. Name = Qt::UserRole + 1
    8. };
    9.  
    10. explicit QMLPtrNotificationModel(QObject *parent = 0);
    11. QMLPtrNotificationModel(const QList<Element*> &list, QObject *parent = 0);
    12. ~QMLPtrNotificationModel();
    13.  
    14. int rowCount(const QModelIndex &parent = QModelIndex()) const;
    15. int count() const { return rowCount(QModelIndex()); }
    16.  
    17. QVariant data(const QModelIndex &index, int role) const;
    18. bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole);
    19.  
    20. Element* at(int index);
    21.  
    22. bool addElement(Element *element);
    23. bool removeElement(Element *element);
    24. bool updateElement(Element *element);
    25. bool clear();
    26.  
    27. public Q_SLOTS:
    28. QList<Element*> getList() const;
    29. void setList(const QList<Element*> &list);
    30.  
    31. private Q_SLOTS:
    32. void refresh();
    33.  
    34. private:
    35. Q_DISABLE_COPY(QMLPtrNotificationModel)
    36. void init();
    37. QList<Element*> lst;
    38. };
    To copy to clipboard, switch view to plain text mode 

    C++ Derived Model:
    Qt Code:
    1. void QMLPtrNotificationModel::init(){
    2. QHash<int, QByteArray> roles;
    3. roles[Name] = "name";
    4. setRoleNames(roles);
    5. }
    6.  
    7. int QMLPtrNotificationModel::rowCount(const QModelIndex &parent) const
    8. {
    9. if (parent.isValid())
    10. return 0;
    11.  
    12. return lst.count();
    13. }
    14.  
    15. QVariant QMLPtrNotificationModel::data(const QModelIndex &index, int role) const
    16. {
    17. if (index.row() < 0 || index.row() > lst.size())
    18. return QVariant();
    19.  
    20. const Element* const elem = lst[index.row()];
    21.  
    22. if (role == Name)
    23. return elem->getName();
    24.  
    25. return QVariant();
    26. }
    27.  
    28. bool QMLPtrNotificationModel::setData(const QModelIndex &index, const QVariant &value, int role)
    29. {
    30. if (index.row() >= 0 && index.row() < lst.size()) {
    31. bool changed = false;
    32.  
    33. Element* const elem = lst.at(index.row());
    34. if(task){
    35. if (role == Name){
    36. changed = true;
    37. elem->setName(value.toString());
    38. }
    39.  
    40. if(changed)
    41. emit dataChanged(index, index);
    42. return changed;
    43. }
    44. return false;
    45. }
    46. return false;
    47. }
    48.  
    49. QList<Element*> QMLPtrNotificationModel::getList() const
    50. {
    51. return lst;
    52. }
    53.  
    54. void QMLPtrNotificationModel::setList(const QList<Element*> &myitems)
    55. {
    56. emit beginResetModel();
    57. lst = myitems;
    58. emit endResetModel();
    59. }
    60.  
    61. bool QMLPtrNotificationModel::clear()
    62. {
    63. beginRemoveRows(QModelIndex(), 0, rowCount());
    64.  
    65. lst.clear();
    66.  
    67. endRemoveRows();
    68. return true;
    69. }
    70.  
    71. bool QMLPtrNotificationModel::addElement(Element *element)
    72. {
    73. int position = rowCount();
    74. beginInsertRows(QModelIndex(), position, position);
    75.  
    76. lst << element;
    77.  
    78. endInsertRows();
    79. return true;
    80. }
    81.  
    82. bool QMLPtrNotificationModel::removeElement(Element *element)
    83. {
    84. int position = lst.indexOf(element);
    85. beginRemoveRows(QModelIndex(), position, position);
    86.  
    87. lst.removeAt(position);
    88.  
    89. endRemoveRows();
    90. return true;
    91. }
    92.  
    93. bool QMLPtrNotificationModel::updateElement(Element *element)
    94. {
    95. int position = lst.indexOf(element);
    96. if(position>-1){
    97. lst[position] = element;
    98.  
    99. emit dataChanged(index(position), index(position));
    100.  
    101. return true;
    102. }
    103. return false;
    104. }
    105.  
    106.  
    107. Element* QMLPtrNotificationModel::at(int index)
    108. {
    109. return lst.at(index);
    110. }
    111.  
    112. void QMLPtrNotificationModel::refresh()
    113. {
    114. QList<Element*> myList = getList();
    115. setList(myList);
    116. }
    To copy to clipboard, switch view to plain text mode 

    After changing the value pointed to by the model i do model.updateElement(elem);
    After deletion/on deletion of the object i do model.removeElement(elem);
    I hope this could be helpful for others who are struggling by implementing an own model for QML

    cheers

  13. #10
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: QML ListModel for interaction with C++

    But why is your Element class derived from QDeclarativeItem?
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


  14. #11
    Join Date
    Nov 2011
    Posts
    26
    Thanks
    6
    Thanked 3 Times in 3 Posts
    Qt products
    Qt3 Qt4 Qt/Embedded Qt Jambi
    Platforms
    Unix/X11 Windows

    Default Re: QML ListModel for interaction with C++

    Because i am using setPos() to place these items in the DeclarativeView

  15. #12
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: QML ListModel for interaction with C++

    They are part of your data and not items. The model makes no use of their declarative item nature. If you delete such an object behind the model's back, your application will crash the next time the model tries to use that item.

    The proper approach would be to have some internal representation of your data that is shared between the model and the item you display somewhere in the scene.
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


  16. #13
    Join Date
    Nov 2011
    Posts
    26
    Thanks
    6
    Thanked 3 Times in 3 Posts
    Qt products
    Qt3 Qt4 Qt/Embedded Qt Jambi
    Platforms
    Unix/X11 Windows

    Default Re: QML ListModel for interaction with C++

    I don't know if i got your point, but that is (as i think) exactly what i do?
    I changed the interface design later to:
    Qt Code:
    1. class QMLPtrAbstractItem : public QDeclarativeItem
    2. {
    3. public:
    4. virtual ~QMLPtrAbstractItem() { }
    5.  
    6. virtual bool setData(int role, const QVariant &value) = 0;
    7. virtual QVariant getData(int role) const = 0;
    8.  
    9. virtual int getUID() const = 0;
    10. virtual void setUID(int uid) = 0;
    11. };
    To copy to clipboard, switch view to plain text mode 

    So that i have an abstract "interface" to the model then i derive other classes of QMLPtrAbstractItem
    Qt Code:
    1. class EmpData : public QMLPtrAbstractItem
    To copy to clipboard, switch view to plain text mode 

    I could have also done:
    Qt Code:
    1. class QMLPtrAbstractItem {}
    2. class EmpData : public QMLPtrAbstractItem, public QDeclarativeItem {}
    To copy to clipboard, switch view to plain text mode 

    But the Abstractlayer is my communication layer between the DeclarativeItem and the Model - or have i missed something?
    I am using only Data in the model - the data i get from the Item itself (i wanted to avoid to implement 3 different model for the same type of use case...

    In the Model i call "getData()" in data() to return the data associated with the provided role (different acting for different item)
    The model holds a list of pointers to the Items (as usual!?) and with data() I request the data for a given role from the selected item

    Isn't that the same behaviour as usual? The same is done here: http://harmattan-dev.nokia.com/docs/...model-cpp.html

    This is what i do: (looks the same for me)
    Qt Code:
    1. QVariant QMLPtrNotificationModel::data(const QModelIndex &index, int role) const
    2. {
    3. if (index.row() < 0 || index.row() > lst.size())
    4. return QVariant();
    5.  
    6. const QMLPtrAbstractItem * const ptrItem = lst[index.row()];
    7.  
    8. return ptrItem->getData(role);
    9. }
    10.  
    11. bool QMLPtrNotificationModel::setData(const QModelIndex &index, const QVariant &value, int role)
    12. {
    13. if (index.row() >= 0 && index.row() < lst.size()) {
    14.  
    15. QMLPtrAbstractItem * const ptrItem = lst.at(index.row());
    16. if(ptrItem){
    17. bool changed = ptrItem->setData(role, value);
    18.  
    19. if(changed)
    20. emit dataChanged(index, index);
    21. return changed;
    22. }
    23. return false;
    24. }else
    25. qDebug() << "QMLPtrNotificationModel::setData( " << role << ")";
    26.  
    27. return false;
    28. }
    To copy to clipboard, switch view to plain text mode 

    What's wrong with that architecture? If you say -you must be right because you have more knowhow than me, but if that's "bad design" i could have missed the point - i am always interested in your opinion

  17. #14
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: QML ListModel for interaction with C++

    You are still using QDeclarativeItem as the base class for items in your model.

    Isn't that the same behaviour as usual? The same is done here: http://harmattan-dev.nokia.com/docs/...model-cpp.html
    No, it's not. In the quoted example Animal is not a subclass of QDeclarativeItem.
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


  18. #15
    Join Date
    Nov 2011
    Posts
    26
    Thanks
    6
    Thanked 3 Times in 3 Posts
    Qt products
    Qt3 Qt4 Qt/Embedded Qt Jambi
    Platforms
    Unix/X11 Windows

    Default Re: QML ListModel for interaction with C++

    Ok.. so you mean this would be better?:
    Qt Code:
    1. class QMLPtrAbstractItem
    2. {
    3. }
    4.  
    5. class QMLPtrNotificationModel : public QAbstractListModel
    6. {
    7. ....
    8. private:
    9. QList<QMLPtrAbstractItem*> lst;
    10. };
    11.  
    12. class EmpData : public QDeclarativeItem, public QMLPtrAbstractItem
    13. {
    14. ....
    15. }
    To copy to clipboard, switch view to plain text mode 

  19. #16
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: QML ListModel for interaction with C++

    What is this EmpData class? Are you adding instances of this class directly to the declarative scene? Your initial QML code suggests the only custom item you are using is "TaskData". How is "EmpData" related to "TaskData"?
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


  20. #17
    Join Date
    Nov 2011
    Posts
    26
    Thanks
    6
    Thanked 3 Times in 3 Posts
    Qt products
    Qt3 Qt4 Qt/Embedded Qt Jambi
    Platforms
    Unix/X11 Windows

    Default Re: QML ListModel for interaction with C++

    EmpData and TaskData are items that i really add to the DeclarativeView - EmpData is not really related to TaskData (That are employees - TaskData are the Tasks that are associated to the Employees which are represented via to the DeclatativeView via EmpData)
    They are however threated similar to Tasks TaskData is created the same way:

    Qt Code:
    1. class TaskData : public QDeclarativeItem, public QMLPtrAbstractItem
    To copy to clipboard, switch view to plain text mode 
    From TaskData there are however again two specifications: Events (sickness, Vacation) and Orders (real working tasks) Task is the "interface for both"

    So OrderData and EventData are then derived from TaskData...
    Qt Code:
    1. EventData *td = new EventData();
    2. td->setUID(ID.toInt());
    3. td->setName(type);
    4. td->setBgColor1("#ffffff");
    5. td->setBgColor2(color.name());
    6. td->setXPos(x);
    7. td->setYPos(y);
    8. td->setLength(w);
    9. td->setCreationUser(creationUser);
    10. taskModel.addElement(td);
    To copy to clipboard, switch view to plain text mode 

    Qt Code:
    1. OrderData *td = new OrderData();
    2. td->setUID(uID);
    3. td->setName(text);
    4. td->setBgColor1("#ffffff");
    5. td->setBgColor2(ZEGlobal->getStatusColor(oid2sta[orderID]).name());
    6. td->setXPos(ex_x);
    7. td->setYPos(ex_y);
    8. td->setLength(len);
    9. td->setOrderID(orderID);
    10. td->setLttID(lttID);
    11. td->setGrpID(grpID);
    12. td->setCreationUser(creationUser);
    13. taskModel.addElement(td);
    To copy to clipboard, switch view to plain text mode 

    These items are later checked for collisions - but i think i got your point ... i don't need the DeclarativeItem ... cauze the items are placed via
    the data from the model in QML..
    Was that your point?

  21. #18
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: QML ListModel for interaction with C++

    Ok, I think the problem is that you are not using QtQuick correctly. It's a declarative framework, not an imperative one. Your TaskData and EmpData classes are delegates -- components that should be used to display (and otherwise interact with) data from a model. They are not supposed to be part of the model itself so you don't need to add them manually to the scene. You just need to state "ok, here is a model containing my data and here is how each item should look like".

    So based on that your EmpData class can have the same base class as your model item class but that's not required in any way, you just need to teach the EmpData class to handle pieces of data from your model. Instead of inheritance you can as well use composition.

    Qt Code:
    1. class EmpDataItem : public QDeclarativeItem {
    2. Q_OBJECT
    3. Q_PROPERTY(QString name READ name WRITE setName)
    4. public:
    5. void setName(const QString &n) {
    6. m_data.name = n;
    7. update();
    8. }
    9. QString name() const { return m_data.name; }
    10. private:
    11. EmpData m_data;
    12. };
    To copy to clipboard, switch view to plain text mode 

    This way you won't require any virtual methods in your data class and you can easily have the model class hold QList<Data> instead of QList<Data*> which makes things a lot easier.
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


  22. #19
    Join Date
    Nov 2011
    Posts
    26
    Thanks
    6
    Thanked 3 Times in 3 Posts
    Qt products
    Qt3 Qt4 Qt/Embedded Qt Jambi
    Platforms
    Unix/X11 Windows

    Default Re: QML ListModel for interaction with C++

    Hmm what you say sounds good so far..
    "Your TaskData and EmpData classes are delegates -- components that should be used to display (and otherwise interact with) data from a model" I agree to that and got that (i think)..
    Means I have Delegates that don't have any data by heart and the delegates are provided X-times according to the Listmodel which holds the data for each Delegate - this might be set via setItemData() correct? And in the delegate I can access the data via the role.

    What for do i need the QDeclarativeItem anyways? If the Delegate interacts with the model that thing is not needed? By now it is working without it..

    If i store the data in the model directly i have to use different model instances - correct? At the moment i am using one instance for Tasks and Events thats why i
    used virtual functions and the Abstractlayer

    What would you do with
    Qt Code:
    1. private:
    2. EmpData m_data;
    3. };
    To copy to clipboard, switch view to plain text mode 
    in the case above ? how does the model interact with that Data?

  23. #20
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: QML ListModel for interaction with C++

    Quote Originally Posted by shock View Post
    and the delegates are provided X-times according to the Listmodel which holds the data for each Delegate
    The delegate is provided once per view using the "delegate" property of the view. The model itself doesn't use a delegate.

    this might be set via setItemData() correct? And in the delegate I can access the data via the role.
    No, that's wrong, that's my point that you are doing it the wrong way. Your model shouldn't be composed of delegates or anything like that. The model holds data, regardless of how the data is stored. You don't need any "items" in the model, the data could be generated on the fly. The "items" are not "delegates", they have no visual representation in the model.

    What for do i need the QDeclarativeItem anyways?
    The way I see it you are providing a custom delegate (TaskData or EmpData). If you implement it in C++, it will be derived from QDeclarativeItem.

    By now it is working without it..
    You have QDeclarativeItem instances all over your code, just take a look.

    If i store the data in the model directly i have to use different model instances
    Different model instances of what?

    how does the model interact with that Data?
    The model doesn't interact with data. The model represents the data, it provides access to it.
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


Similar Threads

  1. Replies: 6
    Last Post: 12th March 2012, 11:06
  2. ListModel.remove() crashes program
    By truefusion in forum Qt Quick
    Replies: 5
    Last Post: 5th February 2012, 16:27
  3. QML and C++ interaction
    By cueMan in forum Qt Programming
    Replies: 3
    Last Post: 11th November 2010, 08:30
  4. UI Interaction gone!
    By zgulser in forum Qt Programming
    Replies: 3
    Last Post: 15th May 2010, 13:08
  5. A simplest ListModel... no example :(
    By tomek in forum Newbie
    Replies: 5
    Last Post: 7th January 2006, 01:32

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Digia, Qt and their respective logos are trademarks of Digia Plc in Finland and/or other countries worldwide.