1
votes

I want to add a column in the last. I want to put QPushButtons to that column. However,I don't know how to do that. Concerns are below.

  1. when I override data(const QModelIndex &index, int role), I have to rewrite all the data, is that avoidable?`

  2. when I return new QPushButton as QVariant, it throw a error message. I don't know how to fix. C:\Qt\5.4\mingw491_32\include\QtCore\qvariant.h:462: error: 'QVariant::QVariant(void*)' is private inline QVariant(void *) Q_DECL_EQ_DELETE;

    QVariant ActionSqlRelationModel::data(const QModelIndex &index, int role) const
    {
        if (role == Qt::DisplayRole)
        {
           return new QPushButton;
        }
        return QVariant();
    }  
    

I try to use QIdentityProxyModel but it occurs error message. I just try to override columncount.

1
It seems I should use QAbstructTableModel and QSqlQuery do that by myself...Woody

1 Answers

1
votes

When I override data(const QModelIndex &index, int role), I have to rewrite all the data, is that avoidable?

Yes. You need to forward to the base class's implementations:

void MyModel : public BaseModel {
public:
  QVariant data(const QModelIndex & index, int role) const Q_DECL_OVERRIDE {
    if (index.column() == BaseModel::columnCount()) {
      // extra column
      return "MyData";
    }
    return BaseModel::data(index, role);
  }
  int columnCount() const Q_DECL_OVERRIDE {
    return BaseModel::columnCount() + 1;
  }
  ...
};

You can also use a QIdentitityProxyModel instead of deriving the base model, and override its methods instead - that way you can easily add your additional column no matter what model is used to keep rest of the data.

Specifically:

void MyProxy : public QIdentityProxyModel {
public:
  QVariant data(const QModelIndex & index, int role) const Q_DECL_OVERRIDE {
    if (index.column() == BaseModel::columnCount()) {
      // extra column
      return "MyData";
    }
    return QIdentityProxyModel::data(index, role);
  }
  int columnCount() const Q_DECL_OVERRIDE {
    return BaseModel::columnCount() + 1;
  }
  MyProxy(QObject * parent = 0) : QIdentityProxyModel(parent) {}
};

You'd then use on the view instead of the original model. To let the proxy know what model it's supposed to act as a proxy for, you use the setSourceModel method. For example:

int main(int argc, char ** argv) {
  QApplication app(argc, argv);
  QTableView view;
  QSqlRelationalTableModel model;
  MyProxy proxy;
  ...
  proxy.setSourceModel(&model);
  view.setModel(&proxy);
  view.show();
  return app.exec();  
}

When I return new QPushButton as QVariant, it throws an error message.

First of all, returning a widget from the data method, even if you manage to do it, is not handled by the views. The views will not use such a widget for anything - they will ignore it. So it won't work. I'm showing below how one might do it, but it's to satisfy your curiosity only - it's a utterly useless exercise. Such code "works", but the widget it returns will be ignored.

If your intention is to show a button as a representation for a certain data item, you need to add a custom delegate to the view. The delegate handles the visualization and widgets of items with non-standard requirements. You must reimplement a QStyledItemDelegate (or QAbstractItemDelegate) and set it on a given column of the view by using setItemDelegateForColumn.

To satisfy your curiosity:

QObject and classes that derive from it are not copyable, and thus cannot be stored directly in a QVariant. Instead, you can store a shared pointer to the object:

typedef QSharedPointer<QPushButton> QPushButtonPtr;
Q_DECLARE_METATYPE(QPushButtonPtr)

...

QVariant ActionSqlRelationModel::data(const QModelIndex &index, int role) const
{
    if (role == Qt::DisplayRole)
    {
       return QPushButtonPtr(new QPushButton);
    }
    return QSqlRelationModel::data(index, role); // underlying class's data
}

I don't quite know what do you want to achieve by storing buttons in a model. It's of course OK to do so, except that none of the views will know what to do with the button that you provide to them.