Локальное хранение данных – SQL
Qt Quick поддерживает API локального хранилища, известное из веб-браузеров как «local storage API». Этот API доступен через import QtQuick.LocalStorage 2.0
.
Как правило, он сохраняет содержимое в базе данных SQLite в месте, зависимом от системы, в файле с уникальным идентификатором на основе заданного имени и версии базы данных. Существующие базы данных невозможно перечислить или удалить. Вы можете найти место хранения из QQmlEngine::offlineStoragePath()
.
Вы используете API, сначала создавая объект базы данных, а затем создавая транзакции в базе данных. Каждая транзакция может содержать один или несколько запросов SQL. Транзакция будет откатываться, когда SQL-запрос не будет выполнен внутри транзакции.
Например, для чтения из простой таблицы заметок с текстовым столбцом вы можете использовать локальное хранилище следующим образом:
import QtQuick
import QtQuick.LocalStorage 2.0
Item {
Component.onCompleted: {
const db = LocalStorage.openDatabaseSync("MyExample", "1.0", "Example database", 10000)
db.transaction( function(tx) {
const result = tx.executeSql('select * from notes')
for(let i = 0; i < result.rows.length; i++) {
print(result.rows[i].text)
}
})
}
}
Сумасшедший прямоугольник
В качестве примера предположим, что мы хотели бы сохранить положение прямоугольника на нашей сцене.
Ниже показана основа примера. Он содержит прямоугольник с названием crazy
, который можно перетаскивать и который показывает в виде текста свое текущее положение по осям x
и y
.
Item {
width: 400
height: 400
Rectangle {
id: crazy
objectName: 'crazy'
width: 100
height: 100
x: 50
y: 50
color: "#53d769"
border.color: Qt.lighter(color, 1.1)
Text {
anchors.centerIn: parent
text: Math.round(parent.x) + '/' + Math.round(parent.y)
}
MouseArea {
anchors.fill: parent
drag.target: parent
}
}
// ...
Вы можете свободно перетаскивать прямоугольник. Когда вы закрываете приложение и запускаете его снова, прямоугольник находится в том же положении.
Теперь мы хотели бы добавить, чтобы позиция x/y прямоугольника хранилась внутри базы данных SQL. Для этого нам нужно добавить функции для работы с базой данных: init
, read
и store
. Эти функции вызываются при завершении создания компонента и при его уничтожении.
import QtQuick
import QtQuick.LocalStorage 2.0
Item {
// ссылка на объект базы данных
property var db
function initDatabase() {
// инициализируем объект базы данных
}
function storeData() {
// сохраняем данные в БД
}
function readData() {
// читаем и применяем данные из БД
}
Component.onCompleted: {
initDatabase()
readData()
}
Component.onDestruction: {
storeData()
}
}
Вы также можете извлечь код работы с БД в собственную JS-библиотеку, которая выполняет всю логику. Это было бы предпочтительным способом, если логика становится более сложной.
В функции инициализации базы данных мы создаем объект БД и обеспечиваем создание таблицы SQL. Обратите внимание, что функции базы данных довольно разговорчивы, так что вы можете следить за ними в консоли.
function initDatabase() {
// инициализируем объект базы данных
print('initDatabase()')
db = LocalStorage.openDatabaseSync("CrazyBox", "1.0", "A box who remembers its position", 100000)
db.transaction( function(tx) {
print('... create table')
tx.executeSql('CREATE TABLE IF NOT EXISTS data(name TEXT, value TEXT)')
})
}
Затем приложение вызывает функцию чтения для чтения существующих данных из базы данных. Здесь нам нужно различать, есть ли уже данные в таблице. Чтобы проверить это, мы смотрим, сколько строк вернул запрос select
.
function readData() {
// читает и применяет данные из БД
print('readData()')
if(!db) { return }
db.transaction(function(tx) {
print('... read crazy object')
const result = tx.executeSql('select * from data where name="crazy"')
if(result.rows.length === 1) {
print('... update crazy geometry')
// получаем столбец значений
const value = result.rows[0].value
// преобразуем в JS-объект
const obj = JSON.parse(value)
// применяем к объекту
crazy.x = obj.x
crazy.y = obj.y
}
})
}
Мы ожидаем, что данные хранятся в строке JSON в столбце value
. Это не типично для SQL, но прекрасно работает с кодом JS. Таким образом, вместо того, чтобы хранить x
, y
как свойства в таблице, мы сохраняем их как полный объект JS, используя методы JSON stringify
/parse
. В итоге мы получаем корректный JS-объект со свойствами x
и y
, которые мы можем применить к нашему сумасшедшему прямоугольнику.
Чтобы сохранить данные, нам нужно различать случаи обновления и вставки. Мы используем обновление, когда запись уже существует, и вставку, если записи с именем "crazy" не существует.
function storeData() {
// сохраняет данные в БД
print('storeData()')
if(!db) { return }
db.transaction(function(tx) {
print('... check if a crazy object exists')
var result = tx.executeSql('SELECT * from data where name = "crazy"')
// подготавливаем объект для сохранения в формате JSON
var obj = { x: crazy.x, y: crazy.y }
if(result.rows.length === 1) { // используем обновление
print('... crazy exists, update it')
result = tx.executeSql('UPDATE data set value=? where name="crazy"', [JSON.stringify(obj)])
} else { // используем вставку
print('... crazy does not exists, create it')
result = tx.executeSql('INSERT INTO data VALUES (?,?)', ['crazy', JSON.stringify(obj)])
}
})
}
Вместо того, чтобы выбирать весь набор записей, мы могли бы также использовать функцию подсчета SQLite, например, SELECT COUNT(*) from data where name = "crazy"
, которая возвращает одну строку с количеством строк, затронутых запросом select
. В противном случае это обычный код SQL. В качестве дополнительной возможности мы используем привязку SQL значения в запросе с помощью ?
.
Теперь вы можете перетаскивать прямоугольник, и когда вы выходите из приложения, база данных сохраняет положение x/y и применяет его при следующем запуске приложения.