Specializing a QAbstractProxyModel for adding a column: the table cells becomes empty

老子叫甜甜 提交于 2019-12-12 02:43:27

问题


I have created a mixin-like proxy model (Qt5) which just adds an extra first column to another proxy model, for adding a QToolBar of actions to each row of the table view (for example, a "delete" button). The model just provides a way of populating a QList<QVariant> for the first column. The delegate must know what is the meaning of each QVariant (usually ints/enums identifying actions), and populate the QToolBar accordingly. As last feature, if there's no actions, no extra column is added (it behaves like a QIdentityProxyModel in that case). Once added, actions cannot be removed. That's a feature for another day.

The problem of today is that, when I insert actions (which I do before setting the model to the view), the cells are all blanks. So, I'm doing something wrong with the signals or who knows with what (I think the mistake is in the add_action function, at the end of the snippet):

template<class proxy_model>
class action_model : public proxy_model
{
    QList<QVariant> l_actions;

public:
    using base_t = proxy_model;
    using base_t::base_t; // Inheriting constructors.

    QModelIndex mapFromSource(const QModelIndex& source_idx) const override
    {
         if (!l_actions.empty() and source_idx.isValid())
            return this->createIndex(source_idx.row(),
                                     source_idx.column() + 1);
         else // identity proxy case
            return base_t::mapFromSource(source_idx);
    } // same for mapToSource but with - 1 instead of + 1.

    int columnCount(const QModelIndex& parent = QModelIndex()) const override
    { return this->base_t::columnCount() + !l_actions.empty(); }

    QVariant headerData(int section, Qt::Orientation orientation, int role) const override
    {
         if (!l_actions.empty()) {

            if (orientation == Qt::Horizontal and section == 0
                and role == Qt::DisplayRole)
                return "Actions"; // Testing.
            else
                return base_t::headerData(section - 1, orientation, role);

         } else // identity proxy case
            return base_t::headerData(section, orientation, role);
    }

    QVariant data(const QModelIndex& idx, int role) const override
    {
        if (!l_actions.empty()) {
            if (idx.column() == 0 and role = Qt::DisplayRole)
                return l_actions; // All the actions for drawing.
            else
                return QVariant();
        } else // identity proxy case
             return base_t::data(idx, role);
    }

    Qt::ItemFlags flags(QModelIndex const& idx) const
    {
        if (!l_actions.empty() and idx.column() == 0)
            return Qt::NoItemFlags; // No editable or selectable
        else
            return base_t::flags(idx);
    }

    // And here, I think, is where the fun starts:
    // The action could be added before or after the sourceModel
    // is set or this model is connected to a view, but I don't
    // how that cases are supposed to be managed.
    void add_action(QVariant const& action)
    {
         bool was_empty = l_actions.empty();
         l_actions << action;

         if (was_empty and !this->insertColumns(0, 1))
            throw std::logic_error("Something went wrong");

         Q_EMIT this->dataChanged
             (this->createIndex(0, 0),
              this->createIndex(this->rowCount(), 0),
              { Qt::DisplayRole });
    }

};

Without setting actions, the model works fine, both with QAbstractIdentityProxyModel and QSortFilterProxyModel as proxy_model. But, when setting actions, the view shows every cell blank, both with QSortFilterProxyModel and QAbstractIdentityProxyModel.

Here is a user-land code:

enum sql_action { DELETE };

auto* table_model = /* My QSqlTableModel */;
auto* view_model = new action_model<QIdentityProxyModel>(my_parent);
auto* table_view = new QTableView;

view_model->add_action(static_cast<int>(sql_action::DELETE));
view_model->setSourceModel(table_model);

table_view->setModel(view_model);
table_view->setSortingEnabled(true);
table_view->setAlternatingRowColors(true);
// The last column is printed in white, not with alternate colors.

table_view->show();
table_model->select();

The delegates are not a problem because I have set no one. I expect a first column with white cells, but I get an entirely white table. The column names are shown fine, except the last one, which prints just 0 as column name.

What am I doing wrong?


回答1:


The problem is in your data() method.

  1. You do not compare role to Qt::DisplayRole you assign to role
  2. If you have actions, you either return the action entry or QVariant(), never any data


来源:https://stackoverflow.com/questions/40987240/specializing-a-qabstractproxymodel-for-adding-a-column-the-table-cells-becomes

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!