2011-01-27 13 views
7

Ho preparato uno QAbstractListModel i cui indici modello contengono un puntatore assolutamente necessario per elaborare i dati. Aggiungo i dati in questo modo:Come associare QModelIndex a una nuova riga?

void PointListModel::addPoint(int frameNumber, QPoint const& pos) 
{ 
    PointItem *pointItem = new PointItem(frameNumber, pos); 
    QModelIndex newRow = this->createIndex(m_points.count(), 0, pointItem); 

    qDebug() << newRow.internalPointer(); 

    beginInsertRows(newRow, m_points.count(), m_points.count()); 
    m_points.insert(m_points.count(), pointItem); 
    endInsertRows(); 

    emit pointAdded(pointItem, pos); 
} 

Fu solo più tardi che mi sono reso conto che l'argomento a beginInsertRows sta chiedendo per l'indice del modello genitore della nuova riga, non indice di modello reale della nuova riga.

Quindi, in questo momento, Qt non mi ha dato modo di fornire un QModelIndex da associare a questa particolare riga. Come creo il mio indice di modello per questa nuova riga?

risposta

6

Ok, sto riscrivendo la mia risposta come dopo alcune ricerche ho scoperto che mi sono sbagliato.

Non si dovrebbe fare nulla di speciale per creare un nuovo indice quando si aggiungono nuovi dati. È il codice dovrebbe essere simile a questo:

PointItem *pointItem = new PointItem(frameNumber, pos); 
// assume you insert a top level row, having no parent 
beginInsertRows(QModelIndex(), m_points.count(), m_points.count()); 
m_points.insert(m_points.count(), pointItem); 
endInsertRows(); 

allora si dovrebbe implementare il metodo index() che creerà indici su richiesta e il metodo parent() che determinerà il genitore di qualche indice, ma dal momento che si dispone di un modello di lista, si dovrebbe probabilmente sempre restituire semplicemente QModelIndex(). Ecco a good article about creating custom models.

Ecco un esempio completo di un QAbstractListModel di lavoro:

class MyModel: public QAbstractListModel { 
    Q_OBJECT 
    public: 
    virtual QModelIndex index(int row, int column = 0, 
     const QModelIndex &parent = QModelIndex()) const; 
    virtual int rowCount(const QModelIndex &parent = QModelIndex()) const; 
    virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; 
    void add(int i); 
    private: 
    QList<int> list; 
}; 

void MyModel::add(int i) 
{ 
    beginInsertRows(QModelIndex(), list.size(), list.size()); 
    list.append(i); 
    endInsertRows(); 
} 

QModelIndex MyModel::index(int row, int column, 
     const QModelIndex &parent) const 
{ 
    return hasIndex(row, column, parent) ? createIndex(row, column, (void*)&list[row]) 
    : QModelIndex(); 
} 

int MyModel::rowCount(const QModelIndex &parent) const 
{ 
    if (parent.isValid()) 
    return 0; 
    return list.size(); 
} 

QVariant MyModel::data(const QModelIndex &index, 
    int role) const 
{ 
    if (!index.isValid()) 
    return QVariant(); 
    if (role != Qt::DisplayRole) 
    return QVariant(); 
    return QVariant(QString::number(*static_cast<int*>(index.internalPointer()))); 
} 
+0

Questo appare come la cosa si fa più vicino a quello che voglio, ma da quanto ho capito, il la funzione index() non è chiamata esclusivamente per la creazione di nuove righe Come faccio a distinguere tra una chiamata index() tra una nuova riga e una esistente? Ho una QMap che memorizza i miei dati, ma la chiave QMap non sta andando per numero di riga al momento. –

+0

@nessup, l'implementazione QAbstractListModel :: index() predefinita chiama sempre createIndex() per qualsiasi coordinata valida, quindi suppongo che si supponga di creare un nuovo indice per ogni chiamata, anche se mi sembra strano anche a me .M tuttavia, l'operazione di creazione dell'indice è considerata poco costosa, quindi è perfettamente corretto creare più indici duplicati. Dopo tutto, l'implementazione sarà la stessa di quella predefinita con l'unica differenza che si passa qualcosa di significativo come il puntatore dati a createIndex() invece di NULL (come l'implementazione predefinita). –

+0

Ok, grazie. Sto tentando di mantenere QMap nel mio codice e restituire un nuovo QModelIndex se QMap non contiene il QModelIndex appropriato in una determinata riga. Ti risponderò su come va. –

2

Ho cucinato un QAbstractListModel cui indici modello contenere un puntatore Sono assolutamente necessario al fine di elaborare i dati.

Se si inizia con i requisiti sbagliate, si finisce con soluzioni sbagliate :)

Un lista modello è abbastanza semplice in modo che non avete bisogno di più di 's row() il QModelIndex di definire in modo univoco i dati dell'indirizzo dell'indice

Quindi, dato un QModelIndexmi, quando prima ha fatto

PointItem * item = static_cast<PointItem*>(mi.internalPointer()); 

si può invece fare

PointItem * item = plm->pointItemFromIndex(mi); 

dove plm è il vostro PointListModel. Se non si dispone di un puntatore ad esso in giro quando è necessario accedere al PointItem, è possibile ricostruire in questo modo:

PointItemModel * plm = qobject_cast<PointItemModel*>(mi.model()); 
// check for !plm here (!mi.isValid() || qobject_cast fails) 

A sua volta, PointListMode::pointItemFromIndex() sarebbe fare il lavoro vero e proprio:

PointItem * PointListMode::pointItemFromindex(const QModelIndex &mi) const { 
    return mi.isValid() ? m_points[mi.row()] : 0 ; 
} 

Questa è la cosa più importante da realizzare quando si lavora con QAbstractListModel in Qt: Sostituire mentalmente QModelIndex con int row, ignorare tutto ciò che ha (un valore non valido QModelIndex ha row() == -1).

Uguale a QAbstractTableModel: ridurre mentalmente lo QModelIndex a int row, int column. Dimentica tutto il resto.

L'unica volta che è necessario il pieno QModelIndex (compresa la sua internalPointer() o internalId() è quando si implementa un modello ad albero (QAbstractItemModel).

Problemi correlati