Results 1 to 7 of 7

Thread: Data Linking and Representation

  1. #1
    Join Date
    Nov 2016
    Posts
    3
    Thanks
    2
    Qt products
    Qt5
    Platforms
    Windows

    Default Data Linking and Representation

    Hey, I'm brand spanking new to Qt and I've been building an application for the past couple of days. I've watched a few videos and read some documentation on how to use some Qt related objects, and all was going well. I've run into a problem now however. I am trying to build a GUI that will allow the user to edit data that's apart of a structure. I'm trying to find the best way to handle this so bare with me while I explain what I am trying to do.

    Currently I have a few structures like this, varying in size ( around 70 vars in some ):

    Qt Code:
    1. typedef struct
    2. {
    3. int health;
    4. int mana;
    5. short stamina;
    6. char active;
    7. int gold;
    8. int level;
    9. int rank;
    10. int group;
    11. float position[ 3 ];
    12. INVENTORY slots[ 5 ];
    13. } PERSON;
    To copy to clipboard, switch view to plain text mode 

    Now I have all of this data dynamically allocated, and pointers for that data stored into a std::map. I have around 20 std::maps that have different data, like an item or another object. Currently I am adding a name for each variable into a QStringList, and displaying it in a ListView. I am trying to link the strings like "Health", "Mana", and "Stamina" to the underlying data type in that structure. An example would be the user double clicks on the string, it would open a new window and ask for input. After the user accepts the input, it would update the underlying data variable in that specific structure so that I could easily save the output into a file.

    The current program flow I have is once the user pushes a button, a ComboBox fills with a list of all of the indexes. After selecting an index the ListView model is set to a QStringList of variable names. From here I am trying to link the QStringList to another model type ( i think ), and then access the structure data by the index value of the selected QModelIndex in the ListView.

  2. #2
    Join Date
    Jan 2008
    Location
    Alameda, CA, USA
    Posts
    5,230
    Thanks
    302
    Thanked 864 Times in 851 Posts
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: Data Linking and Representation

    That sounds bizarrely complicated and unusable. If I understand you correctly, if a user wants to edit a structure with 70 variables, they are going to have to go through 70 different entry dialogs to do it, along with navigating a hierarchy of list and combo boxes to get to the specific field they want to edit? Would you use such an interface more than once or twice before moving on to a better game?

    In my practice, when I have a case where users need to edit a multi-entry data structure, I create a custom widget class that contains all of the relevant editing and label widgets in an attractive and logical layout. In the constructor for that widget, I add an additional argument that accepts a const reference to an instance of the data structure I want to edit. Inside the widget constructor, I copy that to a member variable of the same type. The contents of this member variable will be modified by the editing. If I want to support a reset or undo function, I create two copies of the original data; one that will be edited, and one that is the same as the original that I copy into the editable structure on reset.

    The custom widget contains slots that are connected to the appropriate "done editing" signals of the edit widgets. Each of these will retrieve the new value from the GUI, validate it, and then update the appropriate entry in the editable copy of the data structure.

    If the custom widget is embedded in a QDialog, then when the OK button is clicked, the caller can retrieve the edited copy of the data from the dialog (using a getter method) and copy it into the original structure. If the user clicks cancel, then nothing gets retrieved and copied. If the widget is embedded in something like a toolbox, I'll still usually add an Apply button so the user can commit the changes.

    This copy-edit-retrieve scenario works for most of the cases where multiple related variables must be edited. If you are backing your data up to a database, you'll still need to do something like this to handle the case where the user wants to cancel the edit. If you are dynamically updating the data model with each edit, it's pretty hard to handle the "Oops, I was editing the wrong Person!" case.
    <=== The Great Pumpkin says ===>
    Please use CODE tags when posting source code so it is more readable. Click "Go Advanced" and then the "#" icon to insert the tags. Paste your code between them.

  3. The following user says thank you to d_stranz for this useful post:

    fatsack (28th November 2016)

  4. #3
    Join Date
    Nov 2016
    Posts
    3
    Thanks
    2
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: Data Linking and Representation

    Here's a more somewhat complete code example of what I have, and am trying to do.

    Qt Code:
    1. QStringListModel treeModel;
    2. QStringList treeList;
    3.  
    4. QList< QVariant > varList; // trying to store a pointer to a struct variable
    5.  
    6. std::map< int, PERSON* > personMap;
    7.  
    8. void PopulateTreeNames( )
    9. {
    10. treeList << "Health" << "Mana" << "Gold"; // adding up to 70 items in a structure
    11. treeModel.setStringList( treeList );
    12. ui->listView->setModel( &treeModel );
    13. }
    14.  
    15. void SetTreeReferences( int index )
    16. {
    17. PERSON* pPerson = personMap.at( index ).get( );
    18.  
    19. varList.clear( );
    20.  
    21. // not sure how to store this as a pointer to the structure variable
    22. // using something like &pPerson->health doesn't work
    23. varList << pPerson->health << pPerson->mana << pPerson->gold; // manually adding up to 70 references into this list
    24. }
    25.  
    26. void QT_WIDGET::on_listView_doubleClicked(const QModelIndex &index)
    27. {
    28. // open window, and get user input
    29. int retVal = userInput from Window;
    30.  
    31. // varList should reference the pointer to the var in the structure
    32. varList.at( index ) = retVal;
    33. }
    To copy to clipboard, switch view to plain text mode 

    Hopefully this is a bit easier to understand than my previous post. I am looking for advice on how to cleanly implement this, without having to write too much code for each and every structure variable.

    EDIT:

    Quote Originally Posted by d_stranz View Post
    That sounds bizarrely complicated and unusable. If I understand you correctly, if a user wants to edit a structure with 70 variables, they are going to have to go through 70 different entry dialogs to do it, along with navigating a hierarchy of list and combo boxes to get to the specific field they want to edit? Would you use such an interface more than once or twice before moving on to a better game?
    Saw your post after I finished typing this up. This isn't designed to be used in a game, but rather used as a tool to load and edit data from a binary file. Something like saving a KEYBOARD structure holding information for each key, allowing the user to edit the value of the key in by selecting it from the table view.

    Quote Originally Posted by d_stranz View Post
    In my practice, when I have a case where users need to edit a multi-entry data structure, I create a custom widget class that contains all of the relevant editing and label widgets in an attractive and logical layout. In the constructor for that widget, I add an additional argument that accepts a const reference to an instance of the data structure I want to edit. Inside the widget constructor, I copy that to a member variable of the same type. The contents of this member variable will be modified by the editing. If I want to support a reset or undo function, I create two copies of the original data; one that will be edited, and one that is the same as the original that I copy into the editable structure on reset.
    Could you show or link me to an example of what you mean? I don't really understand what you mean by creating a custom widget class that contains all of the labels.

    The problem I'm having right now is even if I sent a const reference to the instance of a structure, I am trying to link the table view up to the object data in the structure. I feel like this is a bad way of handling it, but I have no idea how else to do it at the moment.
    Last edited by fatsack; 28th November 2016 at 00:21.

  5. #4
    Join Date
    Jan 2006
    Location
    Graz, Austria
    Posts
    8,416
    Thanks
    37
    Thanked 1,544 Times in 1,494 Posts
    Qt products
    Qt3 Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: Data Linking and Representation

    There are a cooupl of options, maybe this one is the easiest:

    Create a QObject derived class that has one Q_PROPERTY for each of your fields, e.g.

    Qt Code:
    1. class PersonAdapter : public QObject
    2. {
    3. Q_OBJECT
    4. Q_PROPERTY(int health READ health WRITE setHealth)
    5.  
    6. public:
    7. // use this in SetTreePreferences
    8. void setPerson(PERSON *person) { m_person = person; }
    9.  
    10.  
    11. // this is the READ function described above
    12. int health() const { return m_person->health; }
    13.  
    14. // this is the WRITE function described above
    15. void setHealth(int health) { m_person->health = health; }
    16.  
    17. private:
    18. PERSON *m_person;
    19. };
    To copy to clipboard, switch view to plain text mode 

    In the slot that retrieves the new value, you need the name of the property to change
    Qt Code:
    1. QByteArray propertyName; // get that e.g. from a list based on the clicked index
    2.  
    3. // m_adapter is an instance of the PersonAdapter class
    4. m_adapter->setProperty(propertyName.constData(), valueFromDialog);
    To copy to clipboard, switch view to plain text mode 

    Cheers,
    _

  6. The following 2 users say thank you to anda_skoa for this useful post:

    d_stranz (28th November 2016), fatsack (28th November 2016)

  7. #5
    Join Date
    Nov 2016
    Posts
    3
    Thanks
    2
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: Data Linking and Representation

    Quote Originally Posted by anda_skoa View Post
    There are a cooupl of options, maybe this one is the easiest:

    Create a QObject derived class that has one Q_PROPERTY for each of your fields, e.g.

    Qt Code:
    1. class PersonAdapter : public QObject
    2. {
    3. Q_OBJECT
    4. Q_PROPERTY(int health READ health WRITE setHealth)
    5.  
    6. public:
    7. // use this in SetTreePreferences
    8. void setPerson(PERSON *person) { m_person = person; }
    9.  
    10.  
    11. // this is the READ function described above
    12. int health() const { return m_person->health; }
    13.  
    14. // this is the WRITE function described above
    15. void setHealth(int health) { m_person->health = health; }
    16.  
    17. private:
    18. PERSON *m_person;
    19. };
    To copy to clipboard, switch view to plain text mode 
    Qt Code:
    1. typedef struct
    2. {
    3. float x;
    4. float y;
    5. float z;
    6. } POSITION;
    7.  
    8. typedef struct
    9. {
    10. int health;
    11. POSITION pos[ 3 ];
    12. } PERSON;
    13.  
    14. class PersonAdapter : public QObject
    15. {
    16. Q_OBJECT
    17. Q_PROPERTY(POSITION position1 READ position1 WRITE setPosition1)
    18. Q_PROPERTY(POSITION position2 READ position2 WRITE setPosition2)
    19. Q_PROPERTY(POSITION position3 READ position3 WRITE setPosition3)
    20.  
    21. public:
    22. // use this in SetTreePreferences
    23. void setPerson(PERSON *person) { m_person = person; }
    24.  
    25.  
    26. // this is the READ function described above
    27. int position1() const { return m_person->position[0]; }
    28. int position2() const { return m_person->position[1]; }
    29. int position3() const { return m_person->position[2]; }
    30.  
    31. // this is the WRITE function described above
    32. void setPosition1(POSITION pos) { m_person->position[0].x = pos.x; m_person->position[0].y = pos.y; m_person->position[0].z = pos.z; }
    33. void setPosition2(POSITION pos) { m_person->position[1].x = pos.x; m_person->position[1].y = pos.y; m_person->position[1].z = pos.z; }
    34. void setPosition3(POSITION pos) { m_person->position[2].x = pos.x; m_person->position[2].y = pos.y; m_person->position[2].z = pos.z; }
    35.  
    36. private:
    37. PERSON *m_person;
    38. };
    To copy to clipboard, switch view to plain text mode 

    With this adapter class, is this how you would handle an array of another structure inside the original structure?

    Quote Originally Posted by anda_skoa View Post
    In the slot that retrieves the new value, you need the name of the property to change
    Qt Code:
    1. QByteArray propertyName; // get that e.g. from a list based on the clicked index
    2.  
    3. // m_adapter is an instance of the PersonAdapter class
    4. m_adapter->setProperty(propertyName.constData(), valueFromDialog);
    To copy to clipboard, switch view to plain text mode 

    Cheers,
    _
    Qt Code:
    1. QStringList treeList;
    2. QStringListModel treeModel;
    3.  
    4. void PopulateTreeNames( )
    5. {
    6. treeList << "Health" << "Mana" << "Gold";
    7. treeModel.setStringList( treeList );
    8. ui->listView->setModel( &treeModel );
    9. }
    10.  
    11. void SetPropertyByName( int index )
    12. {
    13. QByteArray propertyName = treeList.at( index );
    14.  
    15. m_adapter->setProperty( propertyName.constData(), valueFromDialog );
    16. }
    To copy to clipboard, switch view to plain text mode 

    propertyName would be the string equivalent of the index in the ListView's QStringListModel? So the Q_PROPERTY name would need to match whatever I input into the QStringList at the same index, correct?
    Last edited by fatsack; 28th November 2016 at 18:23.

  8. #6
    Join Date
    Jan 2008
    Location
    Alameda, CA, USA
    Posts
    5,230
    Thanks
    302
    Thanked 864 Times in 851 Posts
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: Data Linking and Representation

    propertyName must match (exactly) whatever you have defined as the "name" entry in the Q_PROPERTY macro:

    Qt Code:
    1. Q_PROPERTY(type name
    2. (READ getFunction [WRITE setFunction] |
    3. MEMBER memberName [(READ getFunction | WRITE setFunction)])
    4. [RESET resetFunction]
    5. [NOTIFY notifySignal]
    6. [REVISION int]
    7. [DESIGNABLE bool]
    8. [SCRIPTABLE bool]
    9. [STORED bool]
    10. [USER bool]
    11. [CONSTANT]
    12. [FINAL])
    To copy to clipboard, switch view to plain text mode 

    So in your case:

    Qt Code:
    1. m_adapter->setProperty( "position1", 42 );
    To copy to clipboard, switch view to plain text mode 

    The "MEMBER memberName" variant of the Q_PROPERTY macro allows you to map a user-friendly property name to an internal member variable name, but in that case you can specify either a READ function or a WRITE function, but not both.
    <=== The Great Pumpkin says ===>
    Please use CODE tags when posting source code so it is more readable. Click "Go Advanced" and then the "#" icon to insert the tags. Paste your code between them.

  9. #7
    Join Date
    Jan 2006
    Location
    Graz, Austria
    Posts
    8,416
    Thanks
    37
    Thanked 1,544 Times in 1,494 Posts
    Qt products
    Qt3 Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: Data Linking and Representation

    Quote Originally Posted by fatsack View Post
    [code]
    typedef struct
    {
    float x;
    float y;
    float z;
    } POSITION;
    To use that in a Q_PROPERTY it also needs to be marked with Q_DECLARE_METATYPE and registered with qRegisterMetaType()

    Quote Originally Posted by fatsack View Post
    With this adapter class, is this how you would handle an array of another structure inside the original structure?
    Your position getter functions just return int, not POSITION.

    Quote Originally Posted by fatsack View Post
    propertyName would be the string equivalent of the index in the ListView's QStringListModel?
    That is one way to do it, but you probably want different strings to display.
    So you could either have a list/vector of property names that you use the index's row to access or you store the property name as another role on the entry of the model.

    Cheers,
    _

Similar Threads

  1. Gameboard representation in QT
    By Brando753 in forum Newbie
    Replies: 1
    Last Post: 4th November 2013, 13:37
  2. Replies: 1
    Last Post: 3rd November 2011, 22:17
  3. true representation in binary or hex
    By Tadas in forum Newbie
    Replies: 12
    Last Post: 10th October 2010, 19:02
  4. Graphical representation of an array
    By ithinkso in forum Qt Programming
    Replies: 2
    Last Post: 5th March 2010, 23:30
  5. Tree related representation
    By aegis in forum Qt Programming
    Replies: 1
    Last Post: 12th August 2007, 12:20

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.