Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

How do deal with external changes to a model



  • I have a QAbstractItemModel that represents a list of items from a class looking like this:

    class item {
    public:
        QHash<category, QVariant> values;
    };
    

    These items belong to a a parent class called register, which simultaneously has a list of category objects.
    Each item has a value for each category - categories can be added and removed using a separate QAbstractItemModel subclass.

    Now in a table, all items of a register should be layed out by having one column for each category, where a row corresponds with one item.

    My issue now is - adding a new category in register doesn't go through the item_model, but instead through the category_model, so I'm unsure how to add a column to the item_model.

    I can of course just override insertColumns like this:

    bool item_model::insertColumns(int column, int count, QModelIndex const& parent) {
        beginInsertColumns(parent, column, count);
        endInsertColumns();
    
        return true;
    }
    

    and then execute it like this:

    category_model->insertRows(args);
    item_model->insertColumns(args);
    

    But that seems completely nonsensical. My question is thus - how should I go about adding the columns to the item model?



  • @Folling said in How do deal with external changes to a model:

    doesn't go through the item_model, but instead through the category_model

    What are these models?

    I can of course just override insertColumns like this:

    No you can't. At the time beginInsertColumns is called, columnCount() must return a number of columns inferior by exactly count to when columnCount() is called after endInsertColumns() is executed. Also, the 3rd argument you are passing to beginInsertColumns() is just wrong, it should be column+count-1



  • What are these models?

    They are subclasses of QAbstractItemModel that wrap around the specific item and category objects to provide access to them in list and tableviews.

    No you can't. At the time beginInsertColumns is called, columnCount() must return a number of columns inferior by exactly count to when columnCount() is called after endInsertColumns() is executed.

    Interesting - I didn't know that, however, in that case I could theoretically expose the two functions.

    it should be column+count-1

    Pardon me on that - I wrote the parameters out from my head, since I don't use that approach.

    My current approach is to emit signals from register whenever a category is added, and connect that signal in my item_model. Speaking of that however - that would face the same issue as you mentioned before, given that columnCount() would return the same result prior and after - however it does work as of right now, so perhaps you were mistaken or it's working by accident.



  • An update on this from my side:

    My initial approach wasn't flawless, as @VRonin pointed out, because QAbstractItemModel::columnCount didn't return the appropriate values. I've fixed this, by not immediately passing the new count after inserting the elements to a list, of which the size was used, but instead have the model save exactly how many categories it currently accounts for, so the connection looks like this:

    connect(item_registry.get(), &item_registry::category_added, [this](int position, QSharedPointer<category>) {
        beginInsertColumns(QModelIndex{}, position, position);
        _current_category_count++;
        endInsertColumns();
    });
    

    and likewise columnCount:

    int item_model::columnCount(QModelIndex const&) const {
        if(!_register) {
            qCritical() << "Item-model didn't have a register";
            return 0;
        }
    
        return 1 /* name */ + _current_category_count;
    }