【问题标题】:QAbstractItemModel dynamic item insertionQAbstractItemModel 动态项目插入
【发布时间】:2016-04-27 13:40:56
【问题描述】:

我为我的模型继承了 QAbstractItemModel 类。为了轻松地将新项目插入到模型中,我编写了下一个方法:

void addItem(MyData *parent, MyData *children) {
    QModelIndex idx = createIndex(parent->row(), 0, parent);
    if (!idx.isValid()) {
        return;
    }

    int childCount = parent->getChildCount();
    beginInsertRows(idx, childCount, childCount);
    parent->addChild(children);
    endInsertRows();

    emit layoutChanged(QList<QPersistentModelIndex>{idx});
}

它与 QListView 配合得很好,但是 QML 的 TreeView 在它显示后不会更新值:

int main(int argc, char ** argv) {
    Q_INIT_RESOURCE(ui);
    QApplication application(argc, argv);

    MyModel model;

    for (int i = 0; i < 10; ++ i) {
        MyData *firstLevelItem = new MyData(i);

        for (int k = 0; k < 3; ++ k) {
            MyData *secondLevelItem = new MyData(i);
            model.addItem(firstLevelItem, secondLevelItem);
        }

        model.addItem(model.getRootItem(), firstLevelItem);
    }

    QQuickView view;
    QQmlContext *context = view.rootContext();
    context->setContextProperty("MyModel", &model);

    view.setSource(QUrl("qrc:///ui/form.qml"));
    view.show();

    QTreeView t;
    t.setModel(&model);
    t.show();

    MyData *data = new MyData(2281488);
    model.addItem(model.getRootItem(), data);
    // t displays changes, view - not

    return application.exec();
}

MyData 类:

class MyModel;

class MyData: public QObject {
    Q_OBJECT

public:
    explicit MyData() :
        QObject() {
        _parent = nullptr;
    }

    ~MyData() {
        qDeleteAll(_data);
    }

    // getters / setters

    MyData *getChildItem(int index) const {
        if (index < 0 || index >= _data.size()) {
            return nullptr;
        }

        return _data[index];
    }

    int getChildCount() const {
        return _data.size();
    }

    MyData *parent() const {
        return _parent;
    }

    int row() const {
        if (_parent) {
            return _parent->_data.indexOf(const_cast<MyData *>(this));
        } else {
            return 0;
        }
    }

private:
    void addChild(MyData *data) {
        if (data) {
            if (data->_parent) {
                _parent->removeChild(data);
            }
            data->_parent = this;
            _data << data;
        }
    }

    void removeChild(MyData *data) {
        _data.removeAll(data);
    }

    // some private fields

    MyData *_parent;

    QVector<MyData *> _data;

    friend class MyModel;
};

【问题讨论】:

  • 首先,你不应该在没有封闭fooAboutToBeChanged的情况下发出fooChanged。但即便如此,您也不应该发出布局更改。您已经通过beginInsertRowsendInsertRows 发出rowsAboutToBeInsertedrowsInserted 信号通知客户有关更改。
  • 只使用 begin(end)InsertRows 没有结果。也许 idx 对象有问题?我应该使用行索引作为 parent->row() 还是 0 或其他任何东西?
  • 我并不是说layoutChanged 发射是唯一的问题,但这绝对是一个问题,你不应该这样做 :)
  • 我同意你的观点,layoutChanged() 在处理大数据大小时会导致很大的延迟
  • 只是一个建议:将 QList{idx} 包装到 qRegisterMetaType,正如@KubaOber 所说,发出 layoutChanged 是一个问题

标签: c++ qt qml qabstractitemmodel


【解决方案1】:

QML 的 ListView 不适合显示树状结构,例如目录树。它仅适用于通常从 QAbstractListModel 继承的列表模型。如果您从 QAbstractItemModel 派生模型,则必须对其进行专门化,使其表现得像一个列表。

从 Qt 5.5 开始,QtQuick.Controls (v1.4) 模块中有一个 QML TreeView 组件。你可能想试试这个。

【讨论】:

  • 问题有误。当然我用的是 QTreeView 和 QML 的 TreeView。
猜你喜欢
  • 1970-01-01
  • 2023-04-07
  • 2013-06-03
  • 1970-01-01
  • 2018-06-03
  • 1970-01-01
  • 2011-11-16
  • 1970-01-01
  • 2020-06-12
相关资源
最近更新 更多