C++ 如何覆盖QSqlRelationalTableModel?

C++ 如何覆盖QSqlRelationalTableModel?,c++,database,qt,C++,Database,Qt,我想在最后一行中添加一列。 我想在那一栏加上几个按钮。 然而,我不知道怎么做。 关注点如下 当我重写数据(constqmodelindex&index,int-role)时,我必须重写所有数据,这是可以避免的吗 当我将新的QPushButton作为QVariant返回时,它会抛出一条错误消息。我不知道怎么修理。 C:\Qt\5.4\mingw491\u 32\include\QtCore\qvariant.h:462:错误:“qvariant::qvariant(void*)”是私有内联qvar

我想在最后一行中添加一列。 我想在那一栏加上几个按钮。 然而,我不知道怎么做。 关注点如下

  • 当我重写数据(constqmodelindex&index,int-role)时,我必须重写所有数据,这是可以避免的吗

  • 当我将新的QPushButton作为QVariant返回时,它会抛出一条错误消息。我不知道怎么修理。
    C:\Qt\5.4\mingw491\u 32\include\QtCore\qvariant.h:462:错误:“qvariant::qvariant(void*)”是私有内联qvariant(void*)Q_DECL_EQ_DELETE

    QVariant ActionSqlRelationModel::data(const QModelIndex &index, int role) const
    {
        if (role == Qt::DisplayRole)
        {
           return new QPushButton;
        }
        return QVariant();
    }  
    
  • 我尝试使用QidentityProxy模型,但出现了错误消息。 我只是试图覆盖columncount。

    当我重写数据(constqmodelindex&index,int-role)时,我必须重写所有数据,这是可以避免的吗

    对。您需要转发到基类的实现:

    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;
      }
      ...
    };
    
    您还可以使用
    qidentityproxymodel
    而不是派生基础模型,并替代其方法-这样,您就可以轻松地添加额外的列,无论使用什么模型来保留其余数据

    具体而言:

    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) {}
    };
    
    然后在视图上使用,而不是在原始模型上使用。要让代理知道它应该充当哪个模型的代理,可以使用
    setSourceModel
    方法。例如:

    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();  
    }
    
    当我将新的QPushButton作为QVariant返回时,它会抛出一条错误消息

    首先,从
    data
    方法返回一个小部件,即使您成功地返回了它,视图也不会处理它。视图不会使用这样的小部件做任何事情-他们会忽略它。所以它不会起作用。我在下面展示一个人如何做,但这只是为了满足你的好奇心——这是一个完全无用的练习。这样的代码“有效”,但它返回的小部件将被忽略

    如果要将按钮显示为特定数据项的表示形式,则需要向视图中添加自定义委托。该代理处理具有非标准需求的项目的可视化和小部件。必须重新实现
    QStyledItemDelegate
    (或
    QAbstractItemDelegate
    ),并使用
    setItemDelegateForColumn
    在视图的给定列上设置它

    为了满足您的好奇心:

    QObject
    及其派生的类不可复制,因此不能直接存储在
    QVariant
    中。相反,您可以存储指向对象的共享指针:

    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
    }
    
    typedef QSharedPointer QPushButtonPtr;
    Q_DECLARE_元类型(QPushButtonPtr)
    ...
    QVariant ActionSqlRelationModel::数据(常量QModelIndex和索引,int角色)常量
    {
    如果(角色==Qt::DisplayRole)
    {
    返回QPushButtonPtr(新的QPushButton);
    }
    返回QSqlRelationModel::data(索引,角色);//基础类的数据
    }
    

    我不太清楚通过在模型中存储按钮,您想要实现什么。这样做当然没问题,只是没有一个视图知道如何使用您提供给它们的按钮。

    似乎我应该使用QASstructTableModel和QSqlQuery自己来做……谢谢您的回答。我想你的anwser是我想要的,但我不明白你在说什么。我将尝试了解QidentityProxymodel是如何工作的。还要考虑使用Qptr。@Woody A
    QIdentityProxyModel
    是一个代理:它将请求转发到源模型,然后您可以以任何合适的方式修改请求。通过从
    QIdentityProxyModel
    派生,您可以使用所需的任何源模型。通过直接从源模型派生,您仅限于该模型,而不限于其他模型。使用共享指针存储小部件是将小部件存储在
    QVariant
    中的唯一方法,但我仍然要问:为什么您希望将小部件存储在
    QVariant
    和模型中?没有任何现有视图可以使用这样的小部件!我希望我可以让一行可以按下或检查。通过按该行,它可以显示一个新的小部件。这就是我想要的。您对QIdentityProxyModel功能的解释很有趣。我无法理解模型代理的含义。@Woody从字典中得知:“代理是授权代表另一个人行事的代理或替代品”。在这里,
    QIdentityProxyModel
    是一个可以用来代替原始模型的模型。该模型将为您访问原始模型-您可以通过调用代理上的
    setSourceModel
    方法来设置它。代理可以在任何类型的模型上使用。@Woody“通过按行,它可以显示一个新的小部件。”不,它不能,因为您不能简单地通过模型的
    data
    方法将小部件传递给视图。当然,您可以这样做,但是视图不知道如何处理它,您将拥有大量不需要的小部件,它们什么都不做。