您当前的位置: 首页 >  qt

龚建波

暂无认证

  • 4浏览

    0关注

    313博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

Qt程序设计:多个View共享数据

龚建波 发布时间:2022-07-11 00:10:05 ,浏览量:4

当多个 View 展示同一个数据集中的部分数据项时,其中一个 View 进行了增删改操作,也需要同步到其他的 View。有两种比较简单的解决方案:

方案一:如果都是同一种 View(如都是 ListView),那可以共用一个 Model 实例,通过 Proxy 来辅助完成过滤和选择等操作,实践起来也比较简单,几乎不用自己做额外的同步。

方案二:如果数据项需要同时在 ListView、TreeView 等不同的场景使用,那单个 Model 实例的方式实现起来就很麻烦了,这时可以让多个 Model 持有同一组数据项指针(建议用智能指针),更新之后通知所有关联的 View 进行同步刷新。

本文 Demo 采用方案二共享数据项指针的方式,UI 使用 QML 实现。通过 Model 的 data 接口访问数据时,是可以返回指针的,然后 Delegate 通过指针访问数据项的属性。但是 QML 中没法识别智能指针(至少 Qt5 下测试识别不了),只能从智能指针取出原始指针后返回给 QML。但是 QML Delegate 访问原始指针的属性还有问题,就是初始化或者增删时,可能报属性未定义或者是不存在,所以还是先老老实实从 data 接口返回数据项的属性值,而不是返回指针,这样排查问题也容易。

除了数据项指针,还需要一个对象(DataSource)来关联各个 Model/View,这样在一个 Model/View 中的增删改操作,就能同步到其他 Model/View 中。修改时调用 DataSource 接口修改,同时触发更新信号,关联 Model 收到信号后进行同步。考虑到一般编辑接口是需要 Model 的行列号来定位当前项的,QML 中可以通过 Model 来间接调用 DataSource 的增删改,而不是直接操作 DataSource 的增删改。

DataSource 接口定义如下:

#pragma once
#include 
#include 

struct DataInfo
{
    QString key;
    int value = 0;
};

class DataSource : public QObject
{
    Q_OBJECT
private:
    explicit DataSource(QObject *parent = nullptr);
public:
    ~DataSource();
    static DataSource* getInstance();

    //增删改接口
    void deleteItem(QSharedPointer item);
    void appendItem(const QString &key, int value);
    void appendItem(QSharedPointer item);
    void updateItem(QSharedPointer item);
    //根据value范围查询数据
    QList searchItemByValue(int min, int max);

signals:
    //增删改通知其他view更新
    void itemDeleteNotify(QSharedPointer item);
    void itemAppendNotify(QSharedPointer item);
    void itemUpdateNotify(QSharedPointer item);

private:
    //存储着所有的数据
    QList dataList;
};

View 中操作 Model 的增删改接口:

Button {
    text: "update"
    onClicked: {
        //update更新所有view中的该item
        data_model.updateItemByRow(model.index, "key", 123)
    }
}
Button {
    text: "delete"
    onClicked: {
        //删除item
        data_model.deleteItemByRow(model.index)
    }
}

void DataModel::deleteItemByRow(int row)
{
    if(row < 0 || row >= dataList.size())
        return;
    DataSource::getInstance()->deleteItem(dataList.at(row));
}

void DataModel::updateItemByRow(int row, const QString &key, int value)
{
    if(row < 0 || row >= dataList.size())
        return;
    auto item = dataList.at(row);
    item->key = key;
    item->value = value;
    DataSource::getInstance()->updateItem(item);
}

DataSource 信号通知关联 Model 刷新: 

DataModel::DataModel(QObject *parent)
    : QAbstractListModel(parent)
{
    auto source = DataSource::getInstance();
    connect(source, &DataSource::itemAppendNotify,
            this, [this](QSharedPointer item){
        //符合条件,插入
        if(item->value >= searchMin && item->value = 0){
            beginRemoveRows(QModelIndex(), row, row);
            dataList.removeAt(row);
            endRemoveRows();
        }
    });
    connect(source, &DataSource::itemUpdateNotify,
            this, [this](QSharedPointer item){
        int row = dataList.indexOf(item);
        if(row >= 0){
            //已存在,判断是否需要移除
            if(item->value >= searchMin && item->value value >= searchMin && item->value             
关注
打赏
1655829268
查看更多评论
0.0376s