Results 1 to 16 of 16

Thread: Best approach with model/view implementation

Hybrid View

Previous Post Previous Post   Next Post Next Post
  1. #1
    Join Date
    Jun 2008
    Location
    Glenwood, NJ USA
    Posts
    32
    Thanks
    1
    Thanked 2 Times in 2 Posts
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11

    Default Best approach with model/view implementation

    I am becoming frustrated as I cannot seem to come up with a good way to implement the required functions in my custom data structure to adhere to the specifications of the QAbstractItemModel. I designed this program originally as a console program and it is eventually going to become a network backup simulator for performance analysis. My custom data structure is an undirected acyclic graph of nodes which are the (networks/LANs) which have children (clients/servers) that also have children (NIC cards, storage volumes). They are all Data Movers and are based on the BUSDataMover class. I use polymorphism to make the objects functional.

    Most of the examples use a central repository for data that is typically a QVector or QList of QVariants. Because of the polymorphic behavior and private members at different levels in the object hierarchy, I have tried a number of different ways to implement this and can't come up with anything that makes sense.

    Does anyone have any experience with this that might lend some advice?

    Thanks.
    Andy

  2. #2
    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: Best approach with model/view implementation

    Could you provide some code or at least state what are you having problems with?

  3. #3
    Join Date
    Jun 2008
    Location
    Glenwood, NJ USA
    Posts
    32
    Thanks
    1
    Thanked 2 Times in 2 Posts
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11

    Default Re: Best approach with model/view implementation

    Here is the code thus far. The implementation of the model functions are in datamovers.h and datamovers.cpp. The model is busmodel.h and busmodel.cpp. I hope it is readable by others... My coding style has never been critiqued since I do this for fun. I would welcome it.
    Attached Files Attached Files

  4. #4
    Join Date
    Jun 2008
    Location
    Glenwood, NJ USA
    Posts
    32
    Thanks
    1
    Thanked 2 Times in 2 Posts
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11

    Default Re: Best approach with model/view implementation

    I went back and found the problem. I also made the columnCount(), setData(), and data() virtual along with others requiring polymorphic behaviour. Eventually I will eliminate duplicate data in my application but for now I am using a QVector<QVariant> as my model data staging area. I found the problem to be what I mention above not being virtual along with an oversight on what order objects are constructed. I needed to properly size the QVector<QVariant> in the base class before attempting to use the index operator for QVector to insert columns at specified locations in the base class. I still welcome feedback from more experienced coders...

    Thanks.

  5. #5
    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: Best approach with model/view implementation

    Method once declared virtual is always virtual, so you don't need to redeclare methods that are virtual in base classes as virtual in subclasses.

  6. #6
    Join Date
    Jun 2008
    Location
    Glenwood, NJ USA
    Posts
    32
    Thanks
    1
    Thanked 2 Times in 2 Posts
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11

    Default Re: Best approach with model/view implementation

    I'm sorry Wysota, I should have been more clear about what functions I made virtual. I called a number of the functions in my custom base class by the same name. So for example the setData and data functions for the model call setData and data functions in my custom data base class.

  7. #7
    Join Date
    Jun 2008
    Location
    Glenwood, NJ USA
    Posts
    32
    Thanks
    1
    Thanked 2 Times in 2 Posts
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11

    Default Re: Best approach with model/view implementation

    OK. I have made progress. I can successfully load my data structure into the model. I needed to implement a couple more virtual functions for QAbstractItemModel like headerData and setHeaderData.

    So now I am starting to implement the insertRows() function. It appears that if you start with a beginInsertRows(), execute insertRows(), and then call endInsertRows(), behind the scenes providing that the row/column functionality is correct in the custom data structure, a QModelIndex will be created and the internalPointer will be set by the model. That's fine. But I have a problem. My custom data structure does a number of data validity checks and will not currently allow an empty or default object be created. It seems that I do not have a choice but to further modify my code to add default constructer? Am I correct?

  8. #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: Best approach with model/view implementation

    Quote Originally Posted by awhite1159 View Post
    So now I am starting to implement the insertRows() function. It appears that if you start with a beginInsertRows(), execute insertRows(), and then call endInsertRows(),
    No no no, this is wrong. Your implementation of insertRows() should be calling beginInsertRows() and endInsertRows(), not the external code. Besides those methods are protected, so that wouldn't even be possible.

    My custom data structure does a number of data validity checks and will not currently allow an empty or default object be created. It seems that I do not have a choice but to further modify my code to add default constructer? Am I correct?
    Please explain. If you can't have an "empty" object, then don't reimplement insertRows() as it will be useless for you. Instead implement your own method for inserting rows with data. Or make it possible to insert an "empty" object into the model

  9. #9
    Join Date
    Jun 2008
    Location
    Glenwood, NJ USA
    Posts
    32
    Thanks
    1
    Thanked 2 Times in 2 Posts
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11

    Default Re: Best approach with model/view implementation

    I understand that I cannot execute the beginInsertRows() and endInsertRows() since they are not public but instead protected. It would make sense for me to allow inserting empty objects and if I need to, I will remove the built-in data validity checking that my classes currently have. Right now, as an example, my Net class stores an IP address, Netmask, and it checks to make sure it is not a duplicate IP or an invalid IP. I guess I would need to either handle an exception or move the validity checking code out into Qt and utilize its classes like QRegExp...

    The other approach that you mention which I have also considered but do not know enough about how Qt creates its QModelIndexes is to not use insertRows() and provide my own function. Here is how I think it might work. Below is a code snippet that will help me explain:

    Qt Code:
    1. bool BUSModel::insertRows(int row, int count, const QModelIndex& parent) {
    2. beginInsertRows(parent, row, count);
    3.  
    4. BUSDataMoverItem tmpnet10('L', "NetworkTWELVE", "192.168.12.0", "255.255.255.0", 310000000);
    5.  
    6. endInsertRows();
    7. return true;
    8. }
    To copy to clipboard, switch view to plain text mode 

    Above, I pass the parent, the row (I use rowCount() to append to end of child list.), and the count as 1. I start the beginInsertRows(), add the row to my custom data structure, and then execute an endInsertRows(). The BUSDataMoverItem is a temporary handle that I use to create pointers to BUSDataMover objects. I strip the handle off and use a BUSDataMover* in my child list for each object. Above pass the root item of the tree as the parent and do a append to its child list. Here is the question. Does the model look at the row I am inserting, create an internalPointer to this appended child, create a model index, and update the view? The only thing I have not done is 'emit dataChanged()'

    Do I need to somehow utilize the createIndex() function in my custom insert function? Could the problem be that I really don't have a container where my objects live, I only track them by pointers to the free-store (new/delete).

    This is my base class for the custom data structure and how I establish the hierarcy:
    Qt Code:
    1. //=========================== BUSDataMover Abstract Class ================================
    2. // The base BUSDataMover class
    3. class BUSDataMover {
    4. friend class BUSNetworkSupervisor;
    5. friend class BUSDataMoverItem;
    6. friend ostream& operator<<(ostream&, const BUSDataMover*);
    7.  
    8. public:
    9. BUSDataMover(const string& n, const string& i, BUSDataMover* parent = 0);
    10. BUSDataMover() : mName(""), mIsA(""), qParent(0) {}
    11. virtual ~BUSDataMover();
    12. const string& getName() const { return mName; }
    13. void setName(string& name) { mName = name; }
    14. const int getThruput() { return mThruput; }
    15. virtual void setThruput(int tpkb);
    16. virtual BUSNetId& getNet(int n=0) { }
    17. virtual const string& getIpString(int n=0) { }
    18. virtual const string& getNetmaskString(int n=0) { }
    19. virtual void setIp(const string&, int nn=0) { }
    20. virtual void setnm(const string&, int nn=0) { }
    21. virtual BUSDataMover* addStgV(int, int) { }
    22. virtual BUSDataMover* addNIC(const string&, const string&, int tpkb=0) { }
    23. virtual void handleBUSNetworkMessage(BUSNetworkMessage& m);
    24. virtual map<BUSNetId, BUSDataMover*>& getNodeList() { }
    25. virtual int findCost(const BUSNetId&) { }
    26. virtual void setIn(BUSDataMover* i) { mIn=i; }
    27. virtual void setOut(BUSDataMover* o) { mOut=o; }
    28. BUSDataMover* getIn() { return mIn; }
    29. BUSDataMover* getOut() { return mOut; }
    30. void setIsA(string& isa) { mIsA=isa; }
    31. string& getIsA() { return mIsA; }
    32. virtual map<BUSNetId, BUSDataMover*>::iterator findNode(const BUSNetId&) { }
    33. virtual void addNode(const BUSNetId&, BUSDataMover*, int cost=0) { }
    34. virtual map<BUSNetId, BUSDataMover*>::iterator nodeListEnd() { }
    35. virtual map<BUSNetId, BUSDataMover*>::iterator nodeListBegin() { }
    36. protected:
    37. virtual void print(ostream& o) const;
    38. //============================== Qt members ======================================
    39. public:
    40. BUSDataMover* parent() { return qParent; }
    41. void setParent(BUSDataMover* p) { qParent=p; }
    42. void addChild(BUSDataMover* c) { qChildItems.append(c); }
    43. virtual int columnCount();
    44. QVariant data(int column);
    45. virtual BUSDataMover* child(int row);
    46. bool setData(int column, QVariant data);
    47. virtual int row();
    48. int childCount() { return qChildItems.count(); }
    49. int getIconType() { return qIcon; }
    50. protected:
    51. // The destruction process will utilize this to ensure killing all children.
    52. QList<BUSDataMover*> qChildItems;
    53. BUSDataMover* qParent;
    54. // Icon
    55. int qIcon;
    56. //============================ End Qt members ====================================
    57. private:
    58. string mName;
    59. int mThruput;
    60. string mIsA;
    61. BUSDataMover* mIn;
    62. BUSDataMover* mOut;
    63. };
    To copy to clipboard, switch view to plain text mode 
    Last edited by awhite1159; 3rd July 2008 at 08:43.

  10. #10
    Join Date
    Jun 2008
    Location
    Glenwood, NJ USA
    Posts
    32
    Thanks
    1
    Thanked 2 Times in 2 Posts
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11

    Default Re: Best approach with model/view implementation

    I removed the beginInsertRows() and endInsertRows. I replaced it with an 'emit layoutChanged()' and now it seems to work. Is thier any downside to doing it this way? The insertRows() function I posted above was for test purposes only. Now that I can insert a row, would it be best to put a generic or blank record in and then go back with a setData() or just put the valid data in immediately? I'll be using a dialog to enter the new row.

  11. #11
    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: Best approach with model/view implementation

    Quote Originally Posted by awhite1159 View Post
    I removed the beginInsertRows() and endInsertRows. I replaced it with an 'emit layoutChanged()' and now it seems to work. Is thier any downside to doing it this way?
    Yes, the whole model needs to be reread by the view.

    would it be best to put a generic or blank record in and then go back with a setData() or just put the valid data in immediately? I'll be using a dialog to enter the new row.
    Put the valid data immediately, for instance like this:

    Qt Code:
    1. void myModel::appendNewRow(.... someData){
    2. beginInsertRows(QModelIndex(), rowCount(), rowCount());
    3. MyStruct struct = someData;
    4. m_list << struct; // m_list is the container the model operates on
    5. endInsertRows();
    6. }
    To copy to clipboard, switch view to plain text mode 

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.