2009-09-07 11 views
5

OK, ho uno QStandardItemModel veramente semplice, pieno di alcuni numeri. Sono riuscito a visualizzarlo in un QTableView, va bene. Ho creato un nuovo modello (sottoclasse di QAbstractItemModel o QAbstractProxyModel), che è una specie di livello di un modello esistente: è necessario impostare il modello di origine e questo nuovo livello dovrebbe apportare alcune trasformazioni a quello reale.In QT, i modelli di concatenamento non funzionano come previsto

Il mio problema è che nel livello superiore, diciamo "modello di livello", la funzione membro data(const QModelIndex & index, int role) non viene mai chiamata, tuttavia vorrei modificare i metodi di visualizzazione in base al parametro di ruolo.

Ecco un codice di esempio, che dimostra che il modello originale data(index,role) viene sempre chiamato, mentre il modello del livello è mai data(index,role). Perché? In che modo l'oggetto QTableView "salta" lo data(index,role) del livello superiore?

#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(); 
} 

risposta

6

Poiché QTableView utilizza l'indice del modello per recuperare i dati, probabilmente qualcosa di simile.

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

E si restituisce l'indice modello del modello di origine, invece di un indice per il vostro modello di delega:

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

tenta di convertire l'indice del modello in un'indice per il vostro modello di delega

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

Non dimenticare di riscrivere la mappa alla fonte e mappare dalle funzioni sorgente.


Soluzione

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, vedo. Ho quindi 2 domande: - Come posso raggiungere il mio obiettivo senza creare indici proxy? Mi piacerebbe evitare di creare indici nel modello proxy, perché non ci sarà alcun filtro/ordinamento, ecc. E sarebbe una duplicazione completa degli indici dei modelli originali. - Non vedo come il 'QSortFilterProxyModel' può darmi una mano. Devo codificare la funzione 'data (..)' e, a causa di quanto sopra, ho bisogno anche di codificare 'index (...)'. Cosa 'QSortFilterProxyModel' fa che' QAbstractProxyModel' non è nel mio punto di vista? –

+1

È necessario creare nuovi indici che puntano al modello proxy. QSortFilterProxyMode crea gli indici proxy per te. – TimW

+0

Grazie mille, mapToSource e mapFromSource erano gli occhi del diavolo per me! Funziona come un incantesimo! –

Problemi correlati