Reputation: 107
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.
when I override data(const QModelIndex &index, int role), I have to rewrite all the data, is that avoidable?`
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.
Upvotes: 1
Views: 523
Reputation: 98425
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.
Upvotes: 1