2009-09-07 15 views
5

Muy bien, tengo un QStandardItemModel realmente básico, lleno de algunos números. Logré mostrarlo en un QTableView, está bien. Creé un nuevo modelo (subclase de QAbstractItemModel o QAbstractProxyModel), que es una especie de capa de un modelo existente: es necesario para establecer el modelo de origen, y esta nueva capa debe hacer algunas transformaciones en la real.En QT, los modelos de encadenamiento no funcionan como se esperaba

Mi problema es que en la capa superior, diga "modelo de capa" la función de miembro data(const QModelIndex & index, int role) nunca se llamó, sin embargo, me gustaría modificar los métodos de visualización por el parámetro de función.

Aquí hay un código de muestra, que demuestra que siempre se llama al modelo original data(index,role), mientras que el modelo de capa data(index,role) nunca. ¿Por qué? ¿Cómo puede el objeto QTableView "saltar" el data(index,role) de la capa superior?

#include <QtGui/QApplication> 
#include <QtGui> 
#include <QStandardItemModel> 

class MyModel : public QStandardItemModel 
{ 
public: 
    MyModel(const int r, const int c, QObject* parent = 0) : QStandardItemModel(r,c,parent) {} 
    QVariant data (const QModelIndex & index, int role = Qt::DisplayRole) const { 
     qDebug() << "mymodel data"; 
     return this->itemFromIndex(index)->data(role); 
    } 
}; 

class MyProxyModel : public QAbstractProxyModel 
{ 
public: 

    MyProxyModel(QObject* parent = 0) : QAbstractProxyModel(parent) {} 
    QModelIndex index (int row, int column, const QModelIndex & parent = QModelIndex()) const { 
     return this->sourceModel()->index(row,column,parent); 
    } 
    QModelIndex parent (const QModelIndex & index) const { 
     return this->sourceModel()->parent(index); 
    } 
    QModelIndex mapFromSource (const QModelIndex & sourceIndex) const 
    { 
     return sourceIndex; 
    } 
    QModelIndex mapToSource (const QModelIndex & proxyIndex) const 
    { 
     return proxyIndex; 
    } 
    QVariant data (const QModelIndex & index, int role = Qt::DisplayRole) const { 
     qDebug() << "myproxymodel data"; 
     return this->sourceModel()->data(index,role); 
    } 

    int rowCount (const QModelIndex & parent = QModelIndex()) const { 
     return this->sourceModel()->rowCount(parent); 
    } 
    int columnCount (const QModelIndex & parent = QModelIndex()) const { 
     return this->sourceModel()->columnCount(parent); 
    } 
}; 

int main(int argc, char *argv[]) 
{ 
    QApplication app(argc,argv); 
    MyModel model(8, 2); 
    MyProxyModel mymodel; 
    mymodel.setSourceModel(&model); 

    QTableView tableView; 
    tableView.setModel(&mymodel); 

    tableView.horizontalHeader()->setStretchLastSection(true); 
    for (int row = 0; row < 8; ++row) { 
     for (int column = 0; column < 2; ++column) { 
      QModelIndex index = model.index(row, column, QModelIndex()); 
      model.setData(index, QVariant((row+1) * (column+1))); 
     } 

    } 
    tableView.show(); 
    return app.exec(); 
} 

Respuesta

6

Porque QTableView utiliza el índice del modelo para recuperar los datos, probablemente algo como esto.

QModelIndex index = model->index(row, column, parentIndex); 
index.data(Qt::DisplayRole); 

Y va a devolver el índice de modelo del modelo de código en lugar de un índice a su modelo de poder:

QModelIndex index (int row, int column, const QModelIndex & parent = QModelIndex()) const { 
    return this->sourceModel()->index(row,column,parent); 
} 

intenta convertir el modelo de índice en un índice a su modelo de poder

QModelIndex index (int row, int column, const QModelIndex & parent = QModelIndex()) const { 
    return this->createIndex(row,column,row); 
} 

No olvide volver a escribir el mapa en la fuente y el mapa de las funciones de origen.


Solución

class MyTableProxyModel : public QAbstractProxyModel 
{ 
    Q_OBJECT 
public: 
    MyTableProxyModel (QObject* parent = 0) 
     : QAbstractProxyModel(parent) { 
    } 

    QModelIndex index(int row, int column, const QModelIndex& parent=QModelIndex()) const { 
     return createIndex(row,column,row); 
    } 

    QModelIndex parent(const QModelIndex &index) const { 
     //Works only for non-tree models 
     return QModelIndex(); 
    } 

    QModelIndex mapFromSource(const QModelIndex &source) const { 
     return index(source.row(), source.column(), source.parent()); 
    } 

    QModelIndex mapToSource(const QModelIndex &proxy) const { 
     return (sourceModel()&&proxy.isValid()) 
      ? sourceModel()->index(proxy.row(), proxy.column(), proxy.parent()) 
      : QModelIndex(); 
    } 

    QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const { 
     qDebug() << "myproxymodel data"; 
     return mapToSource(index).data(role); 
    } 

    int rowCount (const QModelIndex & parent = QModelIndex()) const { 
     return sourceModel() ? sourceModel()->rowCount(parent) : 0; 
    } 

    int columnCount (const QModelIndex & parent = QModelIndex()) const { 
     return sourceModel() ? sourceModel()->columnCount(parent) : 0; 
    } 
}; 
+0

Ok, veo. Tengo entonces 2 preguntas: - ¿Cómo puedo lograr mi objetivo sin crear índices proxy? Me gustaría evitar la creación de índices en el modelo proxy, ya que no habrá filtrado/clasificación, etc., y eso sería una duplicación completa de los índices de los modelos originales. - No veo cómo el 'QSortFilterProxyModel' puede ayudarme. Tengo que codificar la función 'data (..)', y debido a lo anterior, también necesito codificar el 'index (...)' también. ¿Qué 'QSortFilterProxyModel' hace eso' QAbstractProxyModel' no en mi punto de vista? –

+1

Necesita crear nuevos índices que apunten al modelo de proxy. QSortFilterProxyMode crea los índices de proxy para usted. – TimW

+0

¡Muchas gracias, mapToSource y mapFromSource eran los ojos del diablo para mí! Eso funciona como un encanto! –

Cuestiones relacionadas