Qt 学习之路 2(92):QML 存储

对于很多应用程序,存储数据的能力是必须的。比如,你需要保存下用户设置的参数等。Qt/C++ 提供了强大的QSettings类,用于将用户数据保存在本地文件或操作系统提供的数据结构中(比如 Windows 的注册表)。但是,Qt Quick 只提供了有限的直接访问本地数据的能力。它没有提供像 C++ 那样,能够直接读写操作系统本地文件的功能,这有点类似于浏览器。因此,在很多应用中,读写文件只能通过 C++ 完成:使用 Qt Quick 实现前端界面,C++ 完成后端实际存储的功能。

另一方面,几乎所有应用程序都需要存储或多或少的数据。这些数据可以存储在本地文件中,也可以存储在本地或者远程的服务器。有些数据很简单(例如很多设置信息都是以键值对的形式存储),另外一些则非常复杂(例如我们想要保存一本书的全部信息,包括书名、作者、出版社、出版年、内容简介,甚至封面信息等)。针对这类数据,Qt Quick 提供了自己的解决方案。

前面我们说到,Qt/C++ 提供了强大的QSettings类。QSettings可以帮助我们以独立于操作系统的方式,将程序数据存储到本地。它利用的是操作系统相关的存储结构,或者是以一种通用的 INI 文件保存。

Qt 5.2 起,QML 引入了一个新的类Settings,顾名思义,它就是QSettings的 QML 版本。值得注意的是,直到目前最新的 Qt 5.5.1,Settings依然是试验性质 API,所以,它的 API 可能会在未来版本中有所变化。使用Settings需要添加import Qt.labs.settings 1.0语句。

下面我们创建一个带有颜色的矩形。用户点击这个矩形时,都会生成一个随机的颜色。当应用程序关闭时,当前颜色会保存在本地;重新打开程序,矩形会显示上一次最后的颜色。当程序第一次启动时,矩形会显示默认颜色 #000000;第二次启动时,将会从Settings读取到存储的值并自动绑定到矩形的属性。这是通过属性别名实现的。

上面的实现中,每次值改变,Settings都会直接存储在本地。很多时候,我们并不希望这种实现,而是希望在我们需要的时候保存即可。为了达到这一目的,我们不能使用属性别名,而是需要提供一个额外的辅助函数,在恰当的时刻调用即可:

Settings同样支持按组分类存储:

类似QSettingsSettings同样根据应用名字、组织名字和域名存储数据。这种区分主要用于操作系统提供的数据结构,例如 Windows 平台的注册表的键值。这些信息需要在 C++ 代码中设置:

Settings适合保存简单的键值对信息,对于复杂的结构化数据显得力不从心。HTML 5 增加了 localStorage API,用于浏览器存储结构化数据。Qt Quick 借鉴了 localStorage API,提供了类似的解决方案,名字也被称为 LocalStorage。为了使用该 API,需要添加语句import QtQuick.LocalStorage 2.0

LocalStorage 使用 SQLite 数据库保存数据。这个数据库的文件按照给定的数据库名字和版本保存在系统的指定位置,使用唯一 ID 标识。但是,系统并不允许列出或删除已创建的数据库。可以使用 C++ 的QQmlEngine::offlineStoragePath()函数查看数据库文件存储路径。

为了使用 SQLite 数据库,首先使用 API 创建数据库对象,然后开始一个事务。每一个事务都可以包含一条或多条 SQL 语句。事务中出现任何失败时,整个事务都会回滚。例如,我们要从一个简单的 notes 表中读取数据,就可以使用下面的代码:

下面的例子中,我们假设需要保存场景中矩形的位置。

我们可以使用鼠标将这个矩形到处拖动。当应用关闭、重新打开时,矩形会出现在关闭时的位置。现在,我们希望将矩形的坐标保存在 SQL 数据库中。为了达到这一目的,我们需要在组件创建完成时初始化一个数据库、读取数据库中的数据,在组件销毁时将其坐标写入数据库。

由于这些代码都是业务逻辑相关的,当然可以将这些数据库相关代码放到一个单独的 JS 文件中。事实上,将它们放在独立的 JS 文件中更好一些,不过这里我们就不涉及这些软件工程方面的问题了。

initDatabase函数中,我们需要完成数据库的初始化,同时要保证数据表存在:

接下来,程序会从数据库读取已有数据。这里需要有一个判断:数据库中是否真的有数据。这里,我们仅仅通过数据的条数来简单判断一下。

我们并没有将组件的坐标值按照 x 和 y 分开存储,而是以 JSON 的格式保存。对于 SQL 而言,这并不算一个好主意,但是能够很好的适用于 JS 代码。所以,为了简单起见,我们利用 JSON 相关函数,将对象转换成 JSON 格式之后才真正写入数据库。在读取时,要反过来将读取到的 JSON 转换成对象之后,才能应用到矩形。

为了保存数据,我们需要区分究竟应该执行插入还是更新。如果已有数据,需要更新;如果没有数据,则需要插入:

上面的代码在检查是否存在数据时,检索出整条记录,我们也可以通过SELECT COUNT(*) from data where name = "crazy"语句,仅仅返回检索条数,来获得更好的性能。关于 SQL 已经超出了本文的范畴,这里不再赘述。在UPDATEINSERT语句中,我们使用了?作为占位符。

下面可以执行程序,看程序是如何运行的。

有关 QML 的存储,我们已经介绍了两种最主要的方式。如果这些还是不能满足你的需求,那么我们还有最后一招,能够满足你的各种奇葩需求:使用 C++ 访问你想访问的任何存储系统。我们会在后面详细介绍如何使用 C++ 扩展 Qt Quick。


http://blog.csdn.net/xcw931924821/article/details/52475742

详细目录 1. 序 2. Qt 简介 3. Hello, world! 4. 信号槽 5. 自定义信号槽 6. Qt 模块简介 7. MainWindow 简介 8. 添加动作 9. 资源文件 10. 对象模型 11. 布局管理器 12. 菜单栏、工具栏和状态栏 13. 对话框简介 14. 对话框数据传递 15. 标准对话框 QMessageBox 16. 深入 Qt5 信号槽新语法 17. 文件对话框 18. 事件 19. 事件的接受与忽略 20. event() 21. 事件过滤器 22. 事件总结 23. 自定义事件 24. Qt 绘制系统简介 25. 画刷和画笔 26. 反走样 27. 渐变 28. 坐标系统 29. 绘制设备 30. Graphics View Framework 31. 贪吃蛇游戏(1) 32. 贪吃蛇游戏(2) 33. 贪吃蛇游戏(3) 34. 贪吃蛇游戏(4) 35. 文件 36. 二进制文件读写 37. 文本文件读写 38. 存储容器 39. 遍历容器 40. 隐式数据共享 41. model/view 架构 42. QListWidget、QTreeWidget 和 QTableWidget 43. QStringListModel 44. QFileSystemModel 45. 模型 46. 视图和委托 47. 视图选择 48. QSortFilterProxyModel 49. 自定义只读模型 50. 自定义可编辑模型 51. 布尔表达式树模型 52. 使用拖放 53. 自定义拖放数据 54. 剪贴板 55. 数据库操作 56. 使用模型操作数据库 57. 可视化显示数据数据 58. 编辑数据库外键 59. 使用流处理 XML 60. 使用 DOM 处理 XML 61. 使用 SAX 处理 XML 62. 保存 XML 63. 使用 QJson 处理 JSON 64. 使用 QJsonDocument 处理 JSON 65. 访问网络(1) 66. 访问网络(2) 67. 访问网络(3) 68. 访问网络(4) 69. 进程 70. 进程间通信 71. 线程简介 72. 线程和事件循环 73. Qt 线程相关类 74. 线程和 QObject 75. 线程总结 76. QMLQtQuick 2 77. QML 语法 78. QML 基本元素 79. QML 组件 80. 定位器 81. 元素布局 82. 输入元素 其他文章 宏定义中的 do {…} while (0) C++:在堆上创建对象,还是在栈上?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值