Results 1 to 20 of 24

Thread: QML ListModel for interaction with C++

Hybrid View

Previous Post Previous Post   Next Post Next Post
  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 Re: QML ListModel for interaction with C++

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

  2. #2
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,360
    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.


  3. #3
    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

  4. #4
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,360
    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.


  5. #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++

    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 

  6. #6
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,360
    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.


  7. #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++

    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?

  8. #8
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,360
    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.


  9. #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++

    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?

  10. #10
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,360
    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.


  11. #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++

    You have QDeclarativeItem instances all over your code, just take a look.
    This is the structure that works for me by now:
    Qt Code:
    1. class QMLPtrAbstractItem : public QObject
    2. {
    3. Q_OBJECT
    4. public:
    5. virtual ~QMLPtrAbstractItem() { }
    6.  
    7. virtual bool setData(int role, const QVariant &value) = 0;
    8. virtual QVariant getData(int role) const = 0;
    9.  
    10. virtual int getUID() const = 0;
    11. virtual void setUID(int uid) = 0;
    12. };
    13.  
    14. class EmpData : public QMLPtrAbstractItem
    15. {
    16. Q_OBJECT
    17. public:
    18. enum EmpRoles {
    19. Name = Qt::UserRole + 1,
    20. UID,
    21. Qualification
    22. };
    23.  
    24. static QHash<int, QByteArray> getQMLRoles(){
    25. QHash<int, QByteArray> roles;
    26. roles[Name] = "name";
    27. roles[UID] = "uid";
    28. roles[Qualification] = "qualification";
    29. return roles;
    30. }
    31.  
    32. EmpData() {}
    33.  
    34. virtual QVariant getData(int role) const {
    35. if (role == Name)
    36. return getName();
    37. else if (role == UID)
    38. return getUID();
    39. else if (role == Qualification)
    40. return getQualification();
    41. return QVariant();
    42. }
    43.  
    44. virtual bool setData(int role, const QVariant &value) {
    45. bool changed = false;
    46. if (role == Name){
    47. changed = true;
    48. setName(value.toString());
    49. }
    50. else if (role == UID){
    51. changed = true;
    52. setUID(value.toInt());
    53. }
    54. else if (role == Qualification){
    55. changed = true;
    56. setQualification(value.toString());
    57. }
    58. return changed;
    59. }
    60.  
    61. private:
    62. .....
    63. };
    64.  
    65. class TaskData : public QMLPtrAbstractItem
    66. {
    67. Q_OBJECT
    68.  
    69. public:
    70. enum TaskRoles {
    71. UID = Qt::UserRole + 1,
    72. Name,
    73. BgColor1,
    74. BgColor2,
    75. XPos,
    76. YPos,
    77. Length,
    78. CreationUser,
    79. OrderType,
    80. Active,
    81. Index
    82. };
    83.  
    84. static QHash<int, QByteArray> getQMLRoles(){
    85. QHash<int, QByteArray> roles;
    86. roles[UID] = "uid";
    87. roles[Name] = "name";
    88. roles[BgColor1] = "bgColor1";
    89. roles[BgColor2] = "bgColor2";
    90. roles[XPos] = "xPos";
    91. roles[YPos] = "yPos";
    92. roles[Length] = "length";
    93. roles[CreationUser] = "creationuser";
    94. roles[OrderType] = "orderType";
    95. roles[Active] = "active";
    96. roles[Index] = "index";
    97. return roles;
    98. }
    99.  
    100. TaskData() {
    101. _bgcolor1 = "#FEFEFE";
    102. _bgcolor2 = "#ededeb";
    103. _active = false;
    104. }
    105. virtual ~TaskData() { }
    106.  
    107. .....
    108.  
    109. QVariant getData(int role) const {
    110. if (role == UID)
    111. return getUID();
    112. else if (role == Name)
    113. return getName();
    114. else if (role == BgColor1)
    115. return getBgColor1();
    116. else if (role == BgColor2)
    117. return getBgColor2();
    118. else if (role == XPos)
    119. return getXPos();
    120. else if (role == YPos)
    121. return getYPos();
    122. else if (role == Length)
    123. return getLength();
    124. else if (role == CreationUser)
    125. return getCreationUser();
    126. else if (role == OrderType)
    127. return getOrderType();
    128. else if (role == Active)
    129. return isActive();
    130. else if (role == Index)
    131. return getIndex();
    132. return QVariant();
    133. }
    134.  
    135. bool setData(int role, const QVariant &value) {
    136. bool changed = false;
    137. if (role == UID){
    138. changed = true;
    139. setUID(value.toInt());
    140. }
    141. else if (role == Name){
    142. changed = true;
    143. setName(value.toString());
    144. }
    145. else if (role == BgColor1){
    146. changed = true;
    147. setBgColor1(value.toString());
    148. }
    149. else if (role == BgColor2){
    150. changed = true;
    151. setBgColor2(value.toString());
    152. }
    153. else if (role == XPos){
    154. changed = true;
    155. setXPos(value.toInt());
    156. }
    157. else if (role == YPos){
    158. changed = true;
    159. setYPos(value.toInt());
    160. }
    161. else if (role == Length){
    162. changed = true;
    163. setLength(value.toInt());
    164. }
    165. else if (role == CreationUser){
    166. changed = true;
    167. setCreationUser(value.toInt());
    168. }
    169. else if (role == OrderType){
    170. changed = true;
    171. setOrderType(value.toInt());
    172. }
    173. else if (role == Active){
    174. changed = true;
    175. setActive(value.toInt());
    176. }
    177. else if (role == Index){
    178. changed = true;
    179. setIndex(value.toInt());
    180. }
    181. return changed;
    182. }
    183.  
    184. private:
    185. ....
    186. };
    187.  
    188. class OrderData : public TaskData
    189. {
    190. Q_OBJECT
    191. ....
    192. }
    193.  
    194. class EventData : public TaskData
    195. {
    196. Q_OBJECT
    197. ...
    198. }
    199.  
    200. class QMLPtrNotificationModel : public QAbstractListModel
    201. {
    202. Q_OBJECT
    203. ....
    204. }
    205.  
    206. QVariant QMLPtrNotificationModel::data(const QModelIndex &index, int role) const
    207. {
    208. if (index.row() < 0 || index.row() > lst.size())
    209. return QVariant();
    210.  
    211. const QMLPtrAbstractItem * const ptrItem = lst[index.row()];
    212.  
    213. return ptrItem->getData(role);
    214. }
    215.  
    216. bool QMLPtrNotificationModel::setData(const QModelIndex &index, const QVariant &value, int role)
    217. {
    218. if (index.row() >= 0 && index.row() < lst.size()) {
    219.  
    220. QMLPtrAbstractItem * const ptrItem = lst.at(index.row());
    221. if(ptrItem){
    222. bool changed = ptrItem->setData(role, value);
    223.  
    224. if(changed)
    225. emit dataChanged(index, index);
    226. return changed;
    227. }
    228. return false;
    229. }else
    230. qDebug() << "QMLPtrNotificationModel::setData( " << role << ")";
    231.  
    232. return false;
    233. }
    To copy to clipboard, switch view to plain text mode 

    QML looks like that:
    Qt Code:
    1. Repeater {
    2. id: tasks
    3. model: taskModel // is registered via context() - holds OrderData and EventData via virtual binding
    4. delegate: TaskData { }
    5. }
    To copy to clipboard, switch view to plain text mode 


    There is no QDeclarativeItem anymore - and it compiles and works
    Different model instances of what?
    Different Model instances: one for OrderData, one for EventData and one for EmpData

    As i think the code will also work if i rename the classes to *Cpp? They just have the same names as the delegates - The QML delegate gets the
    Data from the Model provided in the Repeater via accessing the roles of the model?!

    TaskData.qml:
    Qt Code:
    1. Text {
    2. id: taskName
    3. anchors.centerIn: parent
    4. text: name; // sets the name as text -> accesses the given model and executes data() for the role "name" which returns the name !?
    5. color: "white";
    6. }
    To copy to clipboard, switch view to plain text mode 

    Where is my structural error? =(

    -------------------

    I tried it by renamin the classes to *Cpp - works either
    Qt Code:
    1. class EmpDataCpp : public QMLPtrAbstractItem { ... }
    2. class TaskDataCpp : public QMLPtrAbstractItem { ... }
    3. class OrderDataCpp : public TaskDataCpp { .. .}
    4. class EventDataCpp : public TaskDataCpp { .. .}
    To copy to clipboard, switch view to plain text mode 

    With Delegates:
    Qt Code:
    1. Repeater {
    2. id: empGrid
    3. model: empModel
    4. delegate: Employee { }
    5. }
    6. Repeater {
    7. id: tasks
    8. model: taskModel
    9. delegate: TaskData { }
    10. }
    To copy to clipboard, switch view to plain text mode 
    Last edited by shock; 21st March 2012 at 20:32. Reason: Tried with renaming classes to *Cpp

  12. #12
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,360
    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 making it much more complicated than it needs to be. The item class needs not inherit QObject since you are not using any QObject related functionality in it. Next thing is that your model doesn't do anything fancy, it has functionality similar to QStandardItemModel, so you can use that instead of a custom model you need to care about. Third of all if you really insist on using a custom model class, there is no point in having various subclasses of QMLPtrAbstractItem because neither of these subclasses add anything to their base class functionality. Fourth of all if you get rid of QObject legacy, you can use objects instead of pointers to objects in your model which reduces possibilities of making an error somewhere in code.

    Currently your code is equivalent to:

    Qt Code:
    1. class MyModel : public QStandardItemModel {
    2. public:
    3. MyModel(QObject *parent = 0) : QStandardItemModel(parent) { setColumnCount(1); }
    4. void setRoles(const QHash<int, QByteArray> & roleNames) { setRoleNames(roleNames); }
    5. };
    6.  
    7. enum EmpRoles { Name = Qt::DisplayRole, UID = Qt::UserRole, Qualification };
    8. enum TaskRoles { Name = Qt::DisplayRole, UID = Qt::UserRole, ... }
    9. QHash<int, QByteArray> empNames;
    10. empNames[EmpRoles::Name] = "name";
    11. empNames[EmpRoles::UID] = "uid";
    12. // etc.
    13. MyModel empModel;
    14. empModel.setRoles(empNames);
    15.  
    16.  
    17.  
    18. QHash<int, QByteArray> taskNames;
    19. taskNames[TaskRoles::Name] = "name";
    20. taskNames[TaskRoles::UID] = "uid";
    21. MyModel taskModel;
    22. taskModel.setRoles(taskNames);
    To copy to clipboard, switch view to plain text mode 

    My code seems much shorter and less error prone than yours.
    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, 10:06
  2. ListModel.remove() crashes program
    By truefusion in forum Qt Quick
    Replies: 5
    Last Post: 5th February 2012, 15:27
  3. QML and C++ interaction
    By cueMan in forum Qt Programming
    Replies: 3
    Last Post: 11th November 2010, 07:30
  4. UI Interaction gone!
    By zgulser in forum Qt Programming
    Replies: 3
    Last Post: 15th May 2010, 12:08
  5. A simplest ListModel... no example :(
    By tomek in forum Newbie
    Replies: 5
    Last Post: 7th January 2006, 00: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.