How-to create a persistent settings database in Qt Quick (QML)
Article Metadata
Tested with
Compatibility
Article
This article shows how to store your persistent QML application settings using the Offline Storage API.
How-to create a persistent settings database in Qt Quick (QML)
As applications are opened and closed, it is often necessary to keep a few settings or data persistent, for example usernames and passwords, or simply configuration values. Qt Quick (QML) does not (yet?) have a way to access local files (this is doable through a plugin for example), but offers the Offline Storage API. This storage uses Sqlite databases to store data to disk.
Example Code
Here is an example on how to use this Offline Storage API (see QML Global Object) to create a simple settings database. Each setting is composed of a key (represented as a string) and a value (also a string).
Let's create a small javascript file containing the functions necessary to store and retrieve our settings. This file can then be imported in our QML documents to be used. We will have 3 main functions: initialize() to set up the necessary tables, setSetting(setting,value) to record a setting in the database and getSetting(setting) to retrieve a setting's value.
//storage.js
// First, let's create a short helper function to get the database connection
function getDatabase() {
return openDatabaseSync("MyAppName", "1.0", "StorageDatabase", 100000);
}
// At the start of the application, we can initialize the tables we need if they haven't been created yet
function initialize() {
var db = getDatabase();
db.transaction(
function(tx) {
// Create the settings table if it doesn't already exist
// If the table exists, this is skipped
tx.executeSql('CREATE TABLE IF NOT EXISTS settings(setting TEXT UNIQUE, value TEXT)');
});
}
// This function is used to write a setting into the database
function setSetting(setting, value) {
// setting: string representing the setting name (eg: “username”)
// value: string representing the value of the setting (eg: “myUsername”)
var db = getDatabase();
var res = "";
db.transaction(function(tx) {
var rs = tx.executeSql('INSERT OR REPLACE INTO settings VALUES (?,?);', [setting,value]);
//console.log(rs.rowsAffected)
if (rs.rowsAffected > 0) {
res = "OK";
} else {
res = "Error";
}
}
);
// The function returns “OK” if it was successful, or “Error” if it wasn't
return res;
}
// This function is used to retrieve a setting from the database
function getSetting(setting) {
var db = getDatabase();
var res="";
db.transaction(function(tx) {
var rs = tx.executeSql('SELECT value FROM settings WHERE setting=?;', [setting]);
if (rs.rows.length > 0) {
res = rs.rows.item(0).value;
} else {
res = "Unknown";
}
})
// The function returns “Unknown” if the setting was not found in the database
// For more advanced projects, this should probably be handled through error codes
return res
}
Now, we can use this short library in our QML files. Here is a short example:
import Qt 4.7
import "storage.js" as Storage
Rectangle {
width: 360
height: 360
id: screen
Text {
id: textDisplay
anchors.centerIn: parent
}
Component.onCompleted: {
// Initialize the database
Storage.initialize();
// Sets a value in the database
Storage.setSetting("mySetting","myValue");
// Sets the textDisplay element's text to the value we just set
textDisplay.text = "The value of mySetting is:\n" + Storage.getSetting("mySetting");
}
}
--Slocan 23:40, 29 January 2011 (UTC)


Contents
Molbal - Really useful
It's really really useful, just what I was looking formolbal 22:25, 10 August 2011 (EEST)
Geytjie - sql on Symbian
Hi, really like the idea. Can one use this with a mySql database, or does one need to install sqlite if you need to develop the application for Symbian celphones? And do I need to replace function getDatabase() { return openDatabaseSync("WineGui", "1.0", "StorageDatabase", 100000); } with my dbname, like this?
function getDatabase() { return openDatabaseSync("LollaGui", "1.0", "LollaDb", 100000);
}geytjie 21:52, 19 September 2011 (EEST)
Slocan -
@geytjie: This only works with sqlite databases. You do not need to install sqlite, it is included with Qt/QML, so this works on Symbian (as well as other platforms where Qt/QML works).
return openDatabaseSync("LollaGui", "1.0", "LollaDb", 100000);
would be correct, as you replaced the AppName.Slocan 00:50, 3 November 2011 (EET)
Adrianomgil - Sqlite Access inside C++ context
How can I share the same sqlite database between C++ and QML contexts? My problem is about the crazy filename the offline storage create using md5.
Is there a way to change such name?adrianomgil 22:49, 21 November 2011 (EET)
Hamishwillee - Adrianomgil - try the forums
Hi Adrian
Well, you can always run the query QML side and share the results using any of the sharing methods. No idea if you can actually access the file in C++ - suggest you raise this on the discussion boards in order to get more "eyes" on the problem. If you find a good way of doing this, would be great to extend the article though.
Regards
Hamishhamishwillee 01:37, 22 November 2011 (EET)
Texrat - Can't import js file
I saved the storage.js file to the project root folder, but my MeeGo Harmattan project is unable to import it. Any idea why that would happen?Texrat 00:13, 5 December 2011 (EET)
Never mind-- wrong folder! moved to project subfolder under QML and it works fine.
Hamishwillee - This is useful
I like this article, but it doesn't show everything you might want to do with a database.
There is some more comprehensive code, in the context of a real application, in the articles links from here: http://www.developer.nokia.com/Community/Blogs/blog/nokia-developer-news/2011/11/25/new-guides-and-code-step-through-qt-quick-development-for-desktop-and-symbian
These shows some more complicated settings objects, and how these can be pulled in and out of QML databases into models.hamishwillee 02:16, 5 December 2011 (EET)
Itapadar - Is it Ok to use the default database path ?
Hi,
Is it Ok, to use the default database path of the OfflinestorageApi? Does it use the mass storage or RAM?
I tried setting the OfflineStoragePath, but it doesnt create the databse for me , despite creating the directory structure I want.
{ if (dir.mkpath(QString(customPath))){
}
Also, it returns the desired path when I print with, viewer.engine()->offlineStoragePath(), but it creates and saves the database in some other folder.
Regardsitapadar 13:04, 18 January 2012 (EET)
Tslv - how to populate DB?
Hi, Thanks for the example.
1. What if I want to distribute my app with some data already inside? Let's say I've got list of stores that sell toys. How do I populate my database? Do I write an app that creates database and allows me to put stores inside? :) There must be a better way to do this.
2. Where is this database stored? Inside a file? Which one?
tslv 11:48, 23 January 2012 (EET)
Kwhitefoot - There seems to be some confusion about the name of the database
There seems to be some confusion about where the files are created and some people seem to think that it is important to avoid name collisions, or at least they give that impression.
However, at least on the N9, it doesn't actually matter what you call it unless you have more than one used by the same application because the files are stored in:
/home/user/.local/share/data/${organization-name}/${app-name}/QML/OfflineStorage/Databases/
These two variables can be set in main:
Can anyone give some clear rules about this? The documentation doesn't make it clear what name needs to be used and some projects targetting the N9 use very generic names like "SettingsDB" (Buienradar).kwhitefoot 22:16, 3 November 2012 (EET)
Hamishwillee - I think it matters if you want to be cross platform
According to the docs in QML global object: "These databases are user-specific and QML-specific, but accessible to all QML applications. They are stored in the Databases subdirectory of QDeclarativeEngine::offlineStoragePath(), currently as SQLite databases."
Symbian doesn't have a "public" user specific space, so as I understand it they are in a shared area of the drive (you can check the location here: http://doc.qt.nokia.com/4.7/qdeclarativeengine.html#offlineStoragePath-prop ). If so, its quite possible that name classes could occur. I haven't tried this though - so you'd have to look in the folder (possibly data/QML/OfflineStorage/Databases/ ) .
Note that if you're worried you can set your own path for offline storage to avoid any possible conflicts.
As you say, not an issue on N9 since you get a org and app name specific folder.hamishwillee 07:45, 6 November 2012 (EET)
Kwhitefoot - Avoiding conflicts for cross platform applications.
Then I think that the right thing to do is to add the organization and app name to the database name. that should pretty much eliminate name collisions.
For instance if I made an application called FileMan I might use:
giving a settings file name of
It's probably a good idea to avoid spaces too.kwhitefoot 16:08, 6 November 2012 (EET)
Hamishwillee - Yes it should
Yes, adding the app and org name should sort out the issue.
Symbian won't care
Regards
Hamishhamishwillee 07:57, 7 November 2012 (EET)