2011-01-27 12 views
7

Przygotowałem model QAbstractListModel, którego indeksy modelu zawierają wskaźnik, który absolutnie potrzebowałem do przetwarzania danych. Dodam dane tak:Jak powiązać QModelIndex z nowym wierszem?

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

Dopiero później zdałem sobie sprawę, że argument beginInsertRows prosi o modelu indeksu nowego wiersza, a nie rzeczywista Indeks Model nowy wiersz za rodzic.

W tym momencie Qt nie dało mi możliwości dostarczenia QModelIndex do powiązania z tym konkretnym wierszem. Jak utworzyć własny indeks modelu dla tego nowego wiersza?

Odpowiedz

6

OK, przepisuję moją odpowiedź, ponieważ po pewnych badaniach dowiedziałem się, że źle zrobiłem.

Nie powinieneś robić nic specjalnego, aby utworzyć nowy indeks podczas dodawania nowych danych. You kod powinien wyglądać tak:

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

Następnie należy wdrożyć metodę index() które będą tworzyć indeksy na żądanie i metody parent() który zadecyduje rodzica pewnego indeksu, ale skoro masz model listy, to powinien prawdopodobnie zawsze po prostu wróci QModelIndex(). Oto a good article about creating custom models.

Powyżej znajduje się pełna przykładem sprawnego QAbstractListModel:

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

To wygląda to coraz bliżej do tego, co chcę, ale z tego co rozumiem, Funkcja index() nie jest wywoływana wyłącznie w celu tworzenia nowych wierszy Jak rozróżnić wywołanie index() między nowy wiersz a istniejący? Mam QMap przechowuje moje dane, ale klucz QMap nie idzie numer wiersza w danym momencie: –

+0

@nessup, domyślna implementacja QAbstractListModel :: index() zawsze wywołuje funkcję createIndex() dla wszelkich poprawnych współrzędnych, więc domyślam się, że powinna ona utworzyć nowy indeks dla każdego połączenia, chociaż wydaje mi się to również dziwne .M operacja tworzenia indeksu aybe jest uważana za niedrogą, więc można utworzyć wiele zduplikowanych indeksów. W końcu twoja implementacja będzie taka sama jak domyślna, z tą różnicą, że przekażesz coś znaczącego jako wskaźnik danych do createIndex() zamiast NULL (jak to robi domyślna implementacja). –

+0

Dobra, dziękuję. Zamierzam spróbować zachować QMap w moim kodzie i zwrócić nowy QModelIndex, jeśli QMap nie zawiera odpowiedniego QModelIndex w danym wierszu. Wrócę do ciebie, jak to działa. –

2

Mam ugotował QAbstractListModel której indeksy modelu zawierać wskaźnik I absolutnie niezbędne w celu przetwarzania danych.

Jeśli zaczniesz z niewłaściwych wymagań, możesz skończyć z niewłaściwych rozwiązań :)

lista model jest na tyle prosty, tak że nie trzeba więcej niż QModelIndex „s row() do jednoznacznego zdefiniowania dane, które adresuje do indeksu.

Więc otrzymał QModelIndexmi, gdy zanim zrobił

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

można zamiast robić

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

gdzie plm to PointListModel. Jeśli nie masz wskaźnik do niej leżące wokół gdy trzeba otworzyć PointItem można zrekonstruować tak:

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

Z kolei PointListMode::pointItemFromIndex() zrobi rzeczywistej pracy:

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

Jest to najważniejsza rzecz, którą należy sobie uświadomić podczas pracy z QAbstractListModel w Qt: Wymień zamiennie QModelIndex na int row, zignoruj ​​wszystko, co ma (nieprawidłowy QModelIndex ma row() == -1).

To samo dla QAbstractTableModel: mentalnie zmniejszyć QModelIndex do int row, int column. Zapomnij o wszystkim innym.

Jedynym razem trzeba pełny QModelIndex (w tym jego internalPointer() lub internalId() kiedy wdrożyć model drzewa (QAbstractItemModel).

Powiązane problemy