如何创建用于 QML 的通用对象模型?

2024-05-14

我想知道是否有任何宏或方法如何将 Qt 模型注册为 QObject 的属性。

例如,我有AnimalModel (http://doc.qt.io/qt-5/qtquick-modelviewsdata-cppmodels.html#qabstractitemmodel http://doc.qt.io/qt-5/qtquick-modelviewsdata-cppmodels.html#qabstractitemmodel).

我知道我可以将它传递到 QuickView 的根上下文

QuickView view;
view.rootContext()->setContextProperty("myModel", &model);

如果我通过 Qml 宏注册了 QObject,我也可以传递这个对象来查看:

view.rootContext()->setContextProperty("obj", pDataObject);

但是如果我想要 QObject 保存任何数据的模型怎么办?

例如:

class DataObject : public QObject
{
    Q_OBJECT

    Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
    Q_PROPERTY(QString color READ color WRITE setColor NOTIFY colorChanged)
    ...

    AnimalModel m_modelAnimals;

    //Is this possible in any way?
    //Q_PROPERTY(AnimalModel modelAnimals READ modelAnimals NOTIFY modelAnimalsChanged)
};

到目前为止我发现的每个例子都展示了如何通过QAbstractListModel到根上下文。但没有人知道如何将它用作 QObject 属性。

(我知道有QQmlListProperty but QQmlListProperty不支持部分刷新。总是需要重建所有 Qml 对象)


//Is this possible in any way?
//Q_PROPERTY(AnimalModel modelAnimals READ modelAnimals NOTIFY modelAnimalsChanged)

是的,是的,你没有尝试过吗?当然,这不会是一个AnimalModel but a AnimalModel *,但只要模型继承QAbstractListModel,这就是您所需要的。你甚至不需要NOTIFY无论如何,模型内部的变化都会自动反映。modelAnimalsChanged仅当您用不同的模型替换整个模型时才有意义,并且自然地,关闭 QML 关于在没有通知信号的情况下使用属性的警告。当模型对象没有改变时,执行后者的一种更干净的方法是只返回一个AnimalModel *从插槽或Q_INVOKABLE.

如果您想要一个真正灵活的模型,您可以制作一个可以存储的模型QObject *,然后从 QML 中您可以创建具有任意属性的任意对象,并添加到模型中。然后从模型中你有一个object返回对象的角色,您可以查询并使用该对象来检索它所拥有的属性。虽然“经典”列表模型实现将定义具有静态、固定模式的模型,但使用此方法允许模型中具有具有不同属性的“无定形”对象。

当然,这需要某种类型安全,例如property int type对于此类模型中的每个对象,您可以根据它确定该对象的可用属性。我通常的做法是Loader对于委托,并将对象作为数据源传递给不同的 QML UI 实现,以可视化它实例化的对象类型。这样,您就可以在模型中拥有不同的对象,并将不同的 QML 项作为视图委托。

制作最终的“万事通”列表/模型对象的最后一步是实现QQmlListProperty and Q_CLASSINFO("DefaultProperty", "container")为此,允许您动态地组成列表/模型,或使用 QML 的声明性语法。另请注意,使用此解决方案,您可以在此类模型中添加或删除,甚至删除声明式实例化的对象。

此外,根据您的使用场景,您可能需要qmlRegisterType() or qmlRegisterUncreatableType()对于模型。

好吧,再看一眼,“任何数据的模型”似乎并不是指无模式模型,而只是不同的模式模型。在这种情况下,不要返回AnimalModel *,你可以使用QAbstractListModel *甚至是一个QObject *- 无论如何它都可以在 QML 中工作,因为它通过元系统利用了活力。但无论如何,无模式模型更加强大和灵活,并且不需要定义 C++ 代码,它可以单独通过 QML 工作。

class List : public QAbstractListModel {
    Q_OBJECT
    QList<QObject *> _data;

    Q_PROPERTY(int size READ size NOTIFY sizeChanged)
    Q_PROPERTY(QQmlListProperty<QObject> content READ content)
    Q_PROPERTY(QObject * parent READ parent WRITE setParent)
    Q_CLASSINFO("DefaultProperty", "content")
public:
    List(QObject *parent = 0) : QAbstractListModel(parent) { }
    int rowCount(const QModelIndex &p) const { Q_UNUSED(p) return _data.size(); }
    QVariant data(const QModelIndex &index, int role) const {
        Q_UNUSED(role)
        return QVariant::fromValue(_data[index.row()]);
    }
    QHash<int, QByteArray> roleNames() const {
        static QHash<int, QByteArray> roles = { { Qt::UserRole + 1, "object" } };
        return roles;
    }
    int size() const { return _data.size(); }
    QQmlListProperty<QObject> content() { return QQmlListProperty<QObject>(this, _data); }

public slots:
    void add(QObject * o) { insert(o, _data.size()); }

    void insert(QObject * o, int i) {
        if (i < 0 || i > _data.size()) i = _data.size();
        beginInsertRows(QModelIndex(), i, i);
        _data.insert(i, o);
        o->setParent(this);
        sizeChanged();
        endInsertRows();
    }

    QObject * take(int i) {
        if ((i > -1) && (i < _data.size())) {
            beginRemoveRows(QModelIndex(), i, i);
            QObject * o = _data.takeAt(i);
            o->setParent(0);
            sizeChanged();
            endRemoveRows();
            return o;
        } else qDebug() << "ERROR: take() failed - object out of bounds!";
        return 0;
    }

    QObject * get(int i) {
        if ((i > -1) && (i < _data.size())) return _data[i];
        else  qDebug() << "ERROR: get() failed - object out of bounds!";
        return 0;
    }

    void internalChange(QObject * o) { // added to force sort/filter reevaluation
      int i = _data.indexOf(o);
      if (i == -1) {
        qDebug() << "internal change failed, obj not found";
        return;
      } else {
        dataChanged(index(i), index(i));
      }
    }

signals:
    void sizeChanged();
};

那么,在你之后qmlRegisterType<List>("Core", 1, 0, "List");你几乎可以以任何你想要的方式使用它 - 它可以容纳任何QObject或派生的,自然包括 QMLQtObject可以直接作为模型来驱动ListView。您可以使用插槽或声明式动态填充它,如下所示:

List {
    QtObject { ... }
    QtObject { ... }
    List {
        QtObject { ... }
        QtObject { ... }
    }
}

它还将处理对象所有权,并且您可以轻松地嵌套它,本质上生成一个划分的树模型 - 请注意,您不能使用 QML 声明式地做到这一点ListModel。您可能想添加一个parentChanged如果您想绑定不断变化的父级,则发出信号并实现一个发出它的设置器,在我的情况下没有必要。

至于如何在视图中使用它,您可以使用objectName财产或int type属性或基本上任何区分不同对象类型的方法,并使用Loader对于代表:

Loader {
    // using component in order to capture context props and present to the variable delegate
    sourceComponent: Qt.createComponent(obj.objectName + ".qml")
    // if that is not needed simply use
    // source: obj.objectName + ".qml"
    // or setSource to pass specific properties to delegate properties
    // Component.onCompleted: setSource(obj.objectName + ".qml", {/*prop list*/})
}

Update:

这也是实现的要点 https://stackoverflow.com/a/50690216/991484一个简单且动态且通用的排序和过滤代理与此模型配合使用以增强可用性。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何创建用于 QML 的通用对象模型? 的相关文章

  • C# SmtpClient编程中如何设置带有中文的附件文件名?

    我的代码如下 ContentType ct new ContentType ct MediaType MediaTypeNames Application Octet ct Name 这是一个很长的中文文件名希望能用它在附件名中 Doc A
  • 使用 ADAL v3 使用 ClientID 对 Dynamics 365 进行身份验证

    我正在尝试对我们的在线 Dynamics CRM 进行身份验证以使用可用的 API 我能找到的唯一关于执行此操作的官方文档是 https learn microsoft com en us dynamics365 customer enga
  • C# 中的 Stack<> 实现

    我最近一直在实现递归目录搜索实现 并且使用堆栈来跟踪路径元素 当我使用 string Join 连接路径元素时 我发现它们被颠倒了 当我调试该方法时 我查看了堆栈 发现堆栈内部数组中的元素本身是相反的 即最近 Push 的元素位于内部数组的
  • 如何向 Mono.ZeroConf 注册服务?

    我正在尝试测试 ZeroConf 示例http www mono project com Mono Zeroconf http www mono project com Mono Zeroconf 我正在运行 OpenSuse 11 和 M
  • C# 根据当前日期传递日期时间值

    我正在尝试根据 sql server 中的两个日期获取记录 Select from table where CreatedDate between StartDate and EndDate我通过了5 12 2010 and 5 12 20
  • OpenGL:如何检查用户是否支持glGenBuffers()?

    我检查了文档 它说 OpenGL 版本必须至少为 1 5 才能制作glGenBuffers 工作 用户使用的是1 5版本但是函数调用会导致崩溃 这是文档中的错误 还是用户的驱动程序问题 我正在用这个glGenBuffers 对于VBO 我如
  • 保证复制省略是否适用于函数参数?

    如果我理解正确的话 从 C 17 开始 这段代码现在要求不进行任何复制 Foo myfunc void return Foo auto foo myfunc no copy 函数参数也是如此吗 下面的代码中的副本会被优化掉吗 Foo myf
  • LinkLabel 无下划线 - Compact Framework

    我正在使用 Microsoft Compact Framework 开发 Windows CE 应用程序 我必须使用 LinkLabel 它必须是白色且没有下划线 因此 在设计器中 我将字体颜色修改为白色 并在字体对话框中取消选中 下划线
  • 如何在 Javascript 中连接 C# ActiveX 事件处理程序

    我尝试使用几个代码片段将 ActiveX 对象与 Javascript 事件处理程序挂钩 我无法确定为什么事件处理程序没有被调用 带有项目的 Github 存储库 https github com JesseKPhillips Csharp
  • 让网络摄像头在 OpenCV 中工作

    我正在尝试让我的网络摄像头在 Windows 7 64 位中的 OpenCV 版本 2 2 中捕获视频 但是 我遇到了一些困难 OpenCV 附带的示例二进制文件都无法检测到我的网络摄像头 最近我发现这篇文章表明答案在于重新编译一个文件 o
  • SQLAPI++ 的免费替代品? [关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 是否有任何免费 也许是开源 的替代品SQLAPI http www sqlapi com 这个库看起来
  • ASP.NET Core 中间件与过滤器

    在阅读了 ASP NET Core 中间件之后 我对何时应该使用过滤器以及何时应该使用中间件感到困惑 因为它们似乎实现了相同的目标 什么时候应该使用中间件而不是过滤器 9频道有一个关于此的视频 ASP NET 怪物 91 中间件与过滤器 h
  • 当Model和ViewModel一模一样的时候怎么办?

    我想知道什么是最佳实践 我被告知要始终创建 ViewModel 并且永远不要使用核心模型类将数据传递到视图 这就说得通了 让我把事情分开 但什么是Model 和ViewModel一模一样 我应该重新创建另一个类还是只是使用它 我觉得我应该重
  • 以编程方式创建 Blob 存储容器

    我有一个要求 即在创建公司时 在我的 storageaccount 中创建关联的 blob 存储容器 并将容器名称设置为传入的字符串变量 我已尝试以下操作 public void AddCompanyStorage string subDo
  • 使用 gcc 时在头文件中查找定义的好方法是什么?

    在使用 gcc 时 有人有推荐的方法在头文件中查找定义吗 使用 MSVC 时 我只需右键单击并选择 转到定义 这非常好 我使用过 netbeans gcc 它确实有代码帮助 包括到定义的超链接 所以这是一种选择 但是 我想知道是否有任何其他
  • Xamarin Forms Binding - 访问父属性

    我无法访问页面的 ViewModel 属性以便将其绑定到 IsVisible 属性 如果我不设置 BindingContext 我只能绑定它 有没有办法可以在设置 BindingContext 的同时访问页面的 viewmodel root
  • 在哪里可以找到 Microsoft.Build.Utilities.v3.5

    如何获取 Microsoft Build Utilities v3 5 我正在使用 StyleCop 4 7 Stylecop dll 中的 StyleCop msbuild 任务似乎依赖于 Microsoft Build Utilitie
  • C:设置变量范围内所有位的最有效方法

    让我们来int举个例子 int SetBitWithinRange const unsigned from const unsigned to To be implemented SetBitWithinRange应该返回一个int其中所有
  • 如何从 Windows Phone 7 模拟器获取数据

    我有一个 WP7 的单元测试框架 它在手机上运行 结果相当难以阅读 因此我将它们写入 XDocument 我的问题是 如何才能将这个 XML 文件从手机上移到我的桌面上 以便我可以实际分析结果 到目前为止 我所做的是将 Debugger B
  • 如何在 ASP.NET Core 中注入泛型的依赖关系

    我有以下存储库类 public class TestRepository Repository

随机推荐

  • 使用 Hiveql 循环

    我正在尝试合并 2 个数据集 例如 A 和 B 数据集 A 有一个变量 Flag 它有 2 个值 我并没有只是将两个数据合并在一起 而是尝试根据 标志 变量合并两个数据集 合并代码如下 create table new data as se
  • 在ggplotly散点图中添加自定义数据标签

    我想显示Species对于每个数据点 当光标位于该点上方而不是 x 和 y 值时 我用iris数据集 另外 我希望能够单击数据点以使标签持久存在 并且当我在图中选择新位置时标签不会消失 如果可能的话 最基本的是标签 持久性问题是一个优点 这
  • C++中delete和delete[]的区别[重复]

    这个问题在这里已经有答案了 可能的重复 C 中的删除与删除 运算符 https stackoverflow com questions 2425728 delete vs delete operators in c 我写了一个包含两个指针的
  • 学习 Lisp 的资源 [关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • 解决“Show”类型类实例的隐式问题

    我正在努力使Gender实施Show类型类 scala gt trait Gender extends Show Gender defined trait Gender scala gt case object Male extends G
  • Python 或 C 语言中的 Matlab / Octave bwdist()

    有谁知道 Matlab Octave bwdist 函数的 Python 替代品 此函数返回给定矩阵的每个单元格到最近的非零单元格的欧几里得距离 我看到了一个 Octave C 实现 一个纯 Matlab 实现 我想知道是否有人必须用 AN
  • 在 C# Winforms 应用程序中嵌入 Windows XP 主题

    我有一个旧版 C Windows 窗体应用程序 其布局是根据 Windows XP 默认主题设计的 由于需要将其作为 Citrix 应用程序进行分发 该应用程序现在看起来像经典主题应用程序 因为 Citrix 不鼓励使用主题系统服务 所以
  • 活动加载缓慢

    我的应用程序中有大约 50 个活动 但其中一个活动非常慢 我的意思是当我按下按钮进入该活动时 需要很长时间 有时会出现黑屏 在该活动中 我有一个按钮 如果我单击该按钮 则需要很长时间才能执行 代码很轻 只有一个Button EditText
  • React Native Android 无法连接到 WebSocket

    尽管 Web 实现可以工作 但 android 模拟器以及我的设备无法连接到 WebSocket 在引发错误的地方收到以下事件错误代码 然后断开连接 connection error Event isTrusted false messag
  • iOS 键盘显示后分屏宽度

    我刚刚开始研究 Cordova 应用程序对分屏多任务处理的支持 到目前为止 该应用程序在模拟器中的 iPad 上显示和调整大小都很好 但是当我单击编辑字段并显示软件键盘时 100 宽度的值开始返回整个屏幕 而不是给出的窗口 初始显示 到目前
  • 根据 SSRS 矩阵中的总列计算总列的百分比

    希望在我的 SSRS 矩阵中添加一列 这将为我提供该行中总列的百分比 我正在使用以下表达式 但百分比始终为 100 我假设这是因为总计是最后评估的 所以它只是执行总计 总计 FORMAT Fields ID Value SUM Fields
  • Django和HTML无法从指定时间开始视频

    我正在尝试使用 Django 从特定位置开始播放视频
  • UIApplication.shared.delegate 相当于 SceneDelegate xcode11?

    我在 SceneDelegate 中定义了一个 let 属性 我希望一些 ViewController 能够在场景中访问它 在 UIKit 中 我可以像这样访问 App Delegate 属性 UIApplication shared de
  • 栅格堆叠后如何写入?

    我想操作几个光栅文件 然后再次写入它们 rasterfiles lt list files C data envi full names TRUE d1 lt overlay stack rasterfiles fun function x
  • 选择列表逻辑应位于 ASP.NET MVC、视图、模型或控制器中的什么位置?

    我觉得我的问题与这个问题很接近 但我想对这样的代码应该放在哪里进行更一般的讨论 Asp Net MVC SelectList 重构问题 https stackoverflow com questions 2149855 asp net mv
  • SQL Server:触发器如何读取插入、更新、删除的值

    我在一张表中有触发器并且想阅读UserId插入 更新或删除行时的值 怎么做 下面的代码不起作用 我收到错误UPDATED ALTER TRIGGER dbo UpdateUserCreditsLeft ON dbo Order AFTER
  • 使用 Django Rest Framework 自定义验证错误消息

    DRF 给出的默认验证错误消息是密钥和消息的列表 将此格式自定义为文本格式的最佳方法是什么 例如 这是默认格式 message phone customer with this phone already exists email cust
  • 从 C 结构生成 C# 结构

    我有几十个 C 结构 我需要在 C 中使用它们 典型的 C 结构如下所示 typedef struct UM EVENT ULONG32 Id ULONG32 Orgin ULONG32 OperationType ULONG32 Size
  • 在电子生成器反应电子应用程序后,在 Windows 中出现空白屏幕

    在电子生成器反应电子应用程序后 Windows 中出现空白屏幕 这是package json 在电子生成器反应电子应用程序后 Windows 中出现空白屏幕 name SmallBusinessManagement version 0 1
  • 如何创建用于 QML 的通用对象模型?

    我想知道是否有任何宏或方法如何将 Qt 模型注册为 QObject 的属性 例如 我有AnimalModel http doc qt io qt 5 qtquick modelviewsdata cppmodels html qabstra