I have a custom proxy model that occasionally overhauls itself when a new column/row is added to its source model. From the docs it appears that calling QAbstractItemModel::beginResetModel() and QAbstractItemModel::endResetModel() at the beginning and end of such an operation is the proper methodology. My overhaul function, unfortunately, has several possible exit points and I just know that I'll forget to call endResetModel at every exit point as it gets more complex.

Therefore, I'd like to create a simple RAII class that will call beginResetModel upon construction and then call endResetModel upon destruction, like follows:

class ModelResetter
{
public:
    ModelResetter(QAbstractItemModel* model) : m_model(model)
    {
        m_model->beginResetModel();
    }
    ~ModelResetter()
    {
        m_model->endResetModel();
    }

private:
    QAbstractItemModel* m_model;
};

The problem is that beginResetModel() and endResetModel() are both protected in QAbstractItemModel. Declaring ModelResetter as a friend class in my inherited model doesn't appear to help, since I'm trying to interact with the base class.

I'd rather not do a custom implementation for every model I implement, so can I do this with templates? I'm not very familiar with template syntax yet.

Edit 1: (I removed the sample template code in Edit 2 to avoid confusion)

It'd be nice if I could somehow restrict the template to only allow types that inherit QAbstractItemModel, but I don't see anything in standard C++ that allows that. I will not use Boost.

Edit 2: I guess I wasn't really clear about my requirements. Here they are:

  • Operates on the base class for the general case
  • Enforces the QAbstractItemModel inheritance requirement while in debug mode without penalty in release mode
  • Simple usage with almost no overhead
  • Requires no modification of the base class or new functions
有帮助吗?

解决方案 2

I hate to answer my own question, but after a couple days I put together a template-based solution that fulfills all of my requirements. Yay for my first from-scratch template class. Here's the implementation:

//modelresetter.h
#include <QAbstractItemModel>

/* you must declare this class as a friend to your model
 * to give it access to protected members as follows:
 * template <class Model> friend class ModelResetter;
 */
template<class Model>
class ModelResetter
{
public:
    ModelResetter(Model* model) : m_model(model)
    {
        Q_ASSERT_X(qobject_cast<QAbstractItemModel*>(model) != 0, __FUNCTION__,
                   "templated object does not inherit QAbstractItemModel");
        m_model->beginResetModel();
    }
    ~ModelResetter()
    {
        m_model->endResetModel();
    }

private:
    Model* m_model;
};

and usage:

//mymodel.cpp
bool MyModel::overhaul()
{
    ModelResetter<MyModel> resetter(this); resetter;  //prevent compiler warning

    //do stuff
    if(somethingswrong)
        return false; //model will finish reset at every exit point

    //do more stuff
    return true; //model also completes reset on success
}

Thanks for your help!

其他提示

you could have your inherited model expose methods that would just call beginResetModel() and endResetModel() respectively, then have ModelResetter call those methods.

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top