Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Intended way of storing data in QAbstractTableModel derived class
Forum Update on Monday, May 27th 2025

Intended way of storing data in QAbstractTableModel derived class

Scheduled Pinned Locked Moved Solved General and Desktop
3 Posts 2 Posters 160 Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • K Offline
    K Offline
    keesaev
    wrote on last edited by
    #1

    Hi everyone!
    In this thread I would like to ask you, what is the correct way to store data in custom model.
    Let's say I have a struct of various types, some of which are to be displayed on table:

    struct Item{
        int integer;
        std::string string;
        std::string another_string;
        enum_type some_enum;
        std::string time_stored_in_string;
    };
    

    Then I sublass QAbstractTableModel and store that data in a vector:

    class MyModel : public QAbstractTableModel{
    ...
    std::vector<Item> m_items;
    };
    

    And reimplement data() method:

    QVariant MyModel::data(const QModelIndex& index, int role) const {
          switch (index.column()) {
            case 0: {
              return QDateTime::fromString(QString::fromStdString(m_items[index.row()].time_stored_in_string), "format");
            }
            case 1: {
              return someEnumToQString(m_items[index.row()].some_enum);
            }
            case 2: {
              return QString::fromStdString(m_items[index.row()].string);
            }
            default:
              return QVariant();
          }
    }
    

    As you can see, there's a lot of construction in data() method, we're constructing QString and QDateTime from std::string, and calling some kind of switch-based someEnumToQString method. Also we're not using some of the fields (integer and another_string), but we have to store them for later use.

    Here I am curious of how much of an overhead is this data method? Should I strive to store the data as QVariant for optimization purposes? :

    class MyModel : public QAbstractTableModel{
    ...
    std::vector<std::array<QVariant, 3>> m_items;
    ...
    void addItem(Item const& item){
        // qvariant cast skipped for simplicity
        m_items.emplace_back({
          QDateTime::fromString(QString::fromStdString(item.time_stored_in_string), "format"),
          someEnumToQString(item.some_enum),
          QString::fromStdString(item.string)
        });
    ...
    QVariant data(const QModelIndex& index, int role) const final{
        return m_items[idex.row][index.column];
    }
    };
    

    Feels like pseudocode listed above is closer to intended use, it's for sure faster, but here I lose some of struct members that are going to be needed later, and it is not possible to access members by name anymore, which makes code unreadable.

    A half-measure would be adding some wrapper struct, that would store members used in view as QVariant and others as their original type:

    struct ItemWrapper {
      ItemWrapper(Item const& item) {
          // cast to qvariant
      }
       // used in view
      QVariant string;
      QVariant some_enum;
      QVariant time_stored_in_string;
      // unused in view
      int integer;  
      std::string another_string;
    };
    

    In this case if I need to modify members stored as QVariant, I will have to perform ugly conversion every time

    What are your thoughts on this problem? Should I use wrapper struct for speeding up data() method and losing readability? Or should I ignore overhead brought by first data() implementation as unrelevant?

    VRoninV 1 Reply Last reply
    0
    • K keesaev

      Hi everyone!
      In this thread I would like to ask you, what is the correct way to store data in custom model.
      Let's say I have a struct of various types, some of which are to be displayed on table:

      struct Item{
          int integer;
          std::string string;
          std::string another_string;
          enum_type some_enum;
          std::string time_stored_in_string;
      };
      

      Then I sublass QAbstractTableModel and store that data in a vector:

      class MyModel : public QAbstractTableModel{
      ...
      std::vector<Item> m_items;
      };
      

      And reimplement data() method:

      QVariant MyModel::data(const QModelIndex& index, int role) const {
            switch (index.column()) {
              case 0: {
                return QDateTime::fromString(QString::fromStdString(m_items[index.row()].time_stored_in_string), "format");
              }
              case 1: {
                return someEnumToQString(m_items[index.row()].some_enum);
              }
              case 2: {
                return QString::fromStdString(m_items[index.row()].string);
              }
              default:
                return QVariant();
            }
      }
      

      As you can see, there's a lot of construction in data() method, we're constructing QString and QDateTime from std::string, and calling some kind of switch-based someEnumToQString method. Also we're not using some of the fields (integer and another_string), but we have to store them for later use.

      Here I am curious of how much of an overhead is this data method? Should I strive to store the data as QVariant for optimization purposes? :

      class MyModel : public QAbstractTableModel{
      ...
      std::vector<std::array<QVariant, 3>> m_items;
      ...
      void addItem(Item const& item){
          // qvariant cast skipped for simplicity
          m_items.emplace_back({
            QDateTime::fromString(QString::fromStdString(item.time_stored_in_string), "format"),
            someEnumToQString(item.some_enum),
            QString::fromStdString(item.string)
          });
      ...
      QVariant data(const QModelIndex& index, int role) const final{
          return m_items[idex.row][index.column];
      }
      };
      

      Feels like pseudocode listed above is closer to intended use, it's for sure faster, but here I lose some of struct members that are going to be needed later, and it is not possible to access members by name anymore, which makes code unreadable.

      A half-measure would be adding some wrapper struct, that would store members used in view as QVariant and others as their original type:

      struct ItemWrapper {
        ItemWrapper(Item const& item) {
            // cast to qvariant
        }
         // used in view
        QVariant string;
        QVariant some_enum;
        QVariant time_stored_in_string;
        // unused in view
        int integer;  
        std::string another_string;
      };
      

      In this case if I need to modify members stored as QVariant, I will have to perform ugly conversion every time

      What are your thoughts on this problem? Should I use wrapper struct for speeding up data() method and losing readability? Or should I ignore overhead brought by first data() implementation as unrelevant?

      VRoninV Offline
      VRoninV Offline
      VRonin
      wrote on last edited by
      #2

      @keesaev said in Intended way of storing data in QAbstractTableModel derived class:

      QVariant MyModel::data(const QModelIndex& index, int role) const {
      switch (index.column()) {

      You should also check for role==Qt::DisplayRole or you end up returning the main data even when the view is asking what font to use

      Here I am curious of how much of an overhead is this data method? Should I strive to store the data as QVariant for optimization purposes?

      The overhead is minimal but I would store the QDateTime at construction/assignment time. just my preference though

      Should I strive to store the data as QVariant for optimization purposes?

      Absolutely not, you shouldn't make the foot fit the shoe unless you have some impeding optimisation requirement

      "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
      ~Napoleon Bonaparte

      On a crusade to banish setIndexWidget() from the holy land of Qt

      K 1 Reply Last reply
      3
      • VRoninV VRonin

        @keesaev said in Intended way of storing data in QAbstractTableModel derived class:

        QVariant MyModel::data(const QModelIndex& index, int role) const {
        switch (index.column()) {

        You should also check for role==Qt::DisplayRole or you end up returning the main data even when the view is asking what font to use

        Here I am curious of how much of an overhead is this data method? Should I strive to store the data as QVariant for optimization purposes?

        The overhead is minimal but I would store the QDateTime at construction/assignment time. just my preference though

        Should I strive to store the data as QVariant for optimization purposes?

        Absolutely not, you shouldn't make the foot fit the shoe unless you have some impeding optimisation requirement

        K Offline
        K Offline
        keesaev
        wrote on last edited by
        #3

        @VRonin
        Thanks for the reply!

        You should also check for role==Qt::DisplayRole or you end up returning the main data even when the view is asking what font to use

        I omitted this detail for simplicity, of cource I use roles - for text and for color used by custom delegate

        Absolutely not, you shouldn't make the foot fit the shoe unless you have some impeding optimisation requirement

        Thanks for great advice!

        1 Reply Last reply
        0

        • Login

        • Login or register to search.
        • First post
          Last post
        0
        • Categories
        • Recent
        • Tags
        • Popular
        • Users
        • Groups
        • Search
        • Get Qt Extensions
        • Unsolved