2011-01-27 48 views
7

Tôi đã nấu một số QAbstractListModel có chỉ mục mô hình chứa một con trỏ mà tôi hoàn toàn cần để xử lý dữ liệu. Tôi thêm các dữ liệu như vậy:Làm cách nào để liên kết QModelIndex với hàng mới?

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

Đó là chỉ sau đó tôi nhận ra rằng lập luận để beginInsertRows được yêu cầu chỉ số mô hình mẹ của hàng mới, không phải là hàng mới của mô hình chỉ số thực tế.

Vì vậy, tại thời điểm này, Qt đã không cung cấp cho tôi cách cung cấp QModelIndex để liên kết với hàng cụ thể này. Làm cách nào để tạo chỉ mục mô hình của riêng tôi cho hàng mới này?

Trả lời

6

Được rồi, tôi đang viết lại câu trả lời của mình sau khi một số nghiên cứu tôi phát hiện ra rằng tôi đã hiểu sai.

Bạn không nên làm gì đặc biệt để tạo chỉ mục mới khi bạn thêm dữ liệu mới. Bạn mã nên trông như thế này:

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

Sau đó, bạn nên thực hiện các index() phương pháp này sẽ tạo ra chỉ số theo yêu cầu và các parent() phương pháp đó sẽ xác định cha mẹ của một số chỉ số, nhưng kể từ khi bạn có một mô hình danh sách, nó nên có lẽ luôn luôn chỉ trả lại QModelIndex(). Đây là a good article about creating custom models.

Đây là một ví dụ hoàn chỉnh của một QAbstractListModel làm việc:

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

này trông giống như nó đang trở nên gần gũi hơn với những gì tôi muốn, nhưng từ những gì tôi hiểu, Hàm index() không chỉ được gọi để tạo các hàng mới.Làm thế nào để phân biệt giữa một cuộc gọi index() giữa một hàng mới và một hàng tồn tại? Tôi có một QMap lưu trữ dữ liệu của tôi, nhưng phím QMap sẽ không Theo số hàng tại thời điểm –

+0

@nessup, việc thực hiện chỉ mục QAbstractListModel :: index() mặc định luôn gọi createIndex() cho bất kỳ tọa độ hợp lệ nào, vì vậy tôi đoán nó sẽ tạo chỉ mục mới cho mỗi cuộc gọi, mặc dù nó có vẻ lạ với tôi . M hoạt động tạo chỉ mục aybe được coi là rẻ tiền vì vậy nó hoàn toàn tốt đẹp để tạo ra nhiều chỉ mục trùng lặp. Sau khi tất cả, thực hiện của bạn sẽ giống như một mặc định với sự khác biệt duy nhất mà bạn vượt qua một cái gì đó có ý nghĩa như con trỏ dữ liệu để createIndex() thay vì NULL (như thực hiện mặc định không). –

+0

Ok, cảm ơn. Tôi sẽ cố gắng giữ một QMap trong mã của tôi và trả về một QModelIndex mới nếu QMap không chứa QModelIndex thích hợp tại một hàng nhất định. Tôi sẽ liên lạc lại với bạn về cách nó đi. –

2

Tôi đã nấu chín lên một QAbstractListModel có chỉ số mô hình có chứa một con trỏ tôi hoàn toàn cần thiết để xử lý dữ liệu.

Nếu bạn bắt đầu với yêu cầu sai, bạn kết thúc với các giải pháp sai :)

Một danh sách mô hình đơn giản là đủ để bạn không cần nhiều hơn 's row()QModelIndex để xác định duy nhất dữ liệu mà chỉ mục địa chỉ.

Vì vậy, cho một QModelIndexmi, khi bạn đã làm trước

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

bạn thay vì có thể làm

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

nơi plmPointListModel của bạn. Nếu bạn không có một con trỏ để nó nằm xung quanh khi bạn cần truy cập vào PointItem, bạn có thể tái tạo lại nó như thế này:

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

Đổi lại, PointListMode::pointItemFromIndex() sẽ làm công việc thực tế:

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

Đây là điều quan trọng nhất để nhận ra khi làm việc với QAbstractListModel trong Qt: Cố ý thay thế QModelIndex bằng int row, bỏ qua mọi thứ khác nó có (số QModelIndex không hợp lệ có row() == -1).

Tương tự cho QAbstractTableModel: tinh thần giảm QModelIndex thành int row, int column. Quên mọi thứ khác đi.

Thời gian duy nhất bạn cần có đầy đủ QModelIndex (bao gồm cả của nó internalPointer() hoặc internalId() là khi bạn thực hiện một mô hình cây (QAbstractItemModel).

Các vấn đề liên quan