{"id":2408,"date":"2025-10-14T14:49:29","date_gmt":"2025-10-14T05:49:29","guid":{"rendered":"https:\/\/www.freelifemakers.org\/wordpress\/?p=2408"},"modified":"2025-10-15T11:14:36","modified_gmt":"2025-10-15T02:14:36","slug":"qtexample4-qml-databasesqlite","status":"publish","type":"post","link":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/2025\/10\/14\/qtexample4-qml-databasesqlite\/","title":{"rendered":"[QT]example5-QML-database(SQLite)"},"content":{"rendered":"\n<p>\ud83d\udc49\uae30\ub2a5\uc740 \ubc84\ud2bc \ud074\ub9ad\ud558\uba74 \ud14d\uc2a4\ud2b8 \uc785\ub825 2\uac1c\uc5d0 \uc785\ub825\ub41c \uc815\ubcf4\ub97c \ub85c\uceec \ub370\uc774\ud130\ubca0\uc774\uc2a4\uc5d0 \uc800\uc7a5\ud558\uace0 \ub9ac\uc2a4\ud2b8\ubdf0\uc5d0 \ud45c\uc2dc\ud574\uc90d\ub2c8\ub2e4.<br>The function saves the information entered in the two text inputs to a local database when the button is clicked and displays it in a list view.<\/p>\n\n\n\n<p>\ud83d\udc49 QML\uc790\uccb4\uac00 \ub85c\uceec \ub370\uc774\ud130\ubca0\uc774\uc2a4 \uc5f0\ub3d9\uae30\ub2a5\uc774 \uc788\uc2b5\ub2c8\ub2e4.<br>QML itself has a local database connection function.<\/p>\n\n\n\n<p>\ud83d\udc49\ud504\ub85c\uc81d\ud2b8\uc0dd\uc131 \ud6c4 \uc218\uc815\ud574\uc57c\ud560\uac74 Main.qml\uacfc Screen01.qml,CMakeLists.txt\uc785\ub2c8\ub2e4.<br>After creating the project, the files that need to be modified are Main.qml, Screen01.qml, and CMakeLists.txt.<\/p>\n\n\n\n<p>\ud83d\udc49CMakeLists.txt\ud30c\uc77c\uc5d0\uc11c Screen01.qml\uc744 \uc778\uc2dd\ud558\ub3c4\ub85d \uc124\uc815\ud569\ub2c8\ub2e4.<br>Set the CMakeLists.txt file to recognize Screen01.qml.<\/p>\n\n\n\n<p>\ud83d\udc49Main.qml\uc740 Screen01.qml\uc744 \ubd88\ub7ec\uc624\ub294 \uc5ed\ud560\ub9cc \uc218\ud589\ud569\ub2c8\ub2e4.<br>Main.qml only performs the role of loading Screen01.qml.<\/p>\n\n\n\n<p>\ud83d\udc49\ubaa8\ub4e0 \ub370\uc774\ud130\ucc98\ub9ac\uc640  \uc571\ub514\uc790\uc778\uc740 Screen01.qml\uc5d0\uc11c \uc218\ud589\ud569\ub2c8\ub2e4.<br>All data processing and app design is performed in Screen01.qml.<\/p>\n\n\n\n<p><strong>1.CMakeLists.txt<\/strong><\/p>\n\n\n\n<p>\u2714\ufe0f<strong> \ud504\ub85c\uc81d\ud2b8 \ub514\ub809\ud1a0\ub9ac\ub0b4\uc5d0 qml\/Screen01.qml<\/strong> \ud30c\uc77c\uc744 \ub9cc\ub4ed\ub2c8\ub2e4.<br>Create a file named qml\/Screen01.qml in the project directory.<\/p>\n\n\n\n<p>\u2714\ufe0f <strong>qml\/Screen01.qml<\/strong> \uc774 \ucf54\ub4dc\ub9cc \ucd94\uac00\ud558\uba74 \ub429\ub2c8\ub2e4.<br>Just add this code to qml\/Screen01.qml.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\ncmake_minimum_required(VERSION 3.16)\n\nproject(example5 VERSION 0.1 LANGUAGES CXX)\n\nset(CMAKE_CXX_STANDARD_REQUIRED ON)\n\nfind_package(Qt6 REQUIRED COMPONENTS Quick)\n#--\nfind_package(Qt6 6.5 COMPONENTS Quick REQUIRED)\n\nqt_standard_project_setup(REQUIRES 6.8)\n\nqt_add_executable(appexample5\n    main.cpp\n)\n\nqt_add_qml_module(appexample5\n    URI example5\n    VERSION 1.0\n    QML_FILES\n        Main.qml\n      <strong>  qml\/Screen01.qml<\/strong>\n)\n\n# Qt for iOS sets MACOSX_BUNDLE_GUI_IDENTIFIER automatically since Qt 6.1.\n# If you are developing for iOS or macOS you should consider setting an\n# explicit, fixed bundle identifier manually though.\nset_target_properties(appexample5 PROPERTIES\n#    MACOSX_BUNDLE_GUI_IDENTIFIER com.example.appexample5\n    MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION}\n    MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}\n    MACOSX_BUNDLE TRUE\n    WIN32_EXECUTABLE TRUE\n)\n\ntarget_link_libraries(appexample5\n    PRIVATE Qt6::Quick\n)\n\ninclude(GNUInstallDirs)\ninstall(TARGETS appexample5\n    BUNDLE DESTINATION .\n    LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}\n    RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}\n)\n<\/code><\/pre>\n\n\n\n<p><strong>2.Main.qml<\/strong><\/p>\n\n\n\n<p>\u2714\ufe0f \ubcfc\ub4dc\uccb4 \uc124\uc815 \ub41c \ubd80\ubd84\uc758 \ucf54\ub4dc\ub9cc \uc785\ub825\ud558\uba74 \ub429\ub2c8\ub2e4.<br>You only need to enter the code for the bolded part.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>import QtQuick\nimport QtQuick.Controls\nimport QtQuick.Window\n\nWindow {\n    width: 800\n    height: 600\n    visible: true\n    title: qsTr(\"QML LocalStorage Example\")\n\n  <strong>  Loader {\n        anchors.fill: parent\n        source: \"qml\/Screen01.qml\"  \/\/ \ub85c\uceec QML \ud30c\uc77c \ub85c\ub4dc \/ Local QML file load\n    }<\/strong>\n}\n<\/code><\/pre>\n\n\n\n<p><strong>3.qml\/Screen01.qml<\/strong><\/p>\n\n\n\n<p>\u2714\ufe0f\uc5ec\uae30\uc11c \ub370\uc774\ud130 \uc785\ub825, \uc218\uc815, \uc0ad\uc81c\ub97c \ucc98\ub9ac\ud569\ub2c8\ub2e4.<br>This is where you enter, edit, and delete data.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>import QtQuick\nimport QtQuick.Controls\nimport QtQuick.Layouts\nimport QtQuick.LocalStorage\n\nRectangle {\n    id: root\n    width: 800\n    height: 600\n    color: \"#EAEAEA\"\n\n    property var db\n    property int selectedId: -1  \/\/ \uc120\ud0dd\ub41c \ub808\ucf54\ub4dc ID \/ Seclected Record ID\n\n    Component.onCompleted: {\n        db = LocalStorage.openDatabaseSync(\"ExampleLocalDB\", \"1.0\", \"Local DB Example\", 1000000)\n        db.transaction(function(tx) {\n            tx.executeSql(\"CREATE TABLE IF NOT EXISTS records(id INTEGER PRIMARY KEY AUTOINCREMENT, text1 TEXT, text2 TEXT)\")\n        })\n        loadData()\n    }\n\n    \/\/ DB\uc5d0\uc11c \ub370\uc774\ud130 \ubd88\ub7ec\uc624\uae30\n    \/\/ Retrieving data from DB\n    function loadData() {\n        db.transaction(function(tx) {\n            const rs = tx.executeSql(\"SELECT * FROM records ORDER BY id DESC\")\n            listModel.clear()\n            for (let i = 0; i &lt; rs.rows.length; i++) {\n                listModel.append({\n                    id: rs.rows.item(i).id,\n                    text1: rs.rows.item(i).text1,\n                    text2: rs.rows.item(i).text2\n                })\n            }\n            selectedId = -1\n        })\n    }\n\n    \/\/ DB\uc5d0 \uc0c8 \ub370\uc774\ud130 \ucd94\uac00\n    \/\/ Add new data to DB\n    function insertData(t1, t2) {\n        if (t1.trim() === \"\" || t2.trim() === \"\") {\n            console.log(\"\uc785\ub825\uac12\uc774 \ube44\uc5b4 \uc788\uc2b5\ub2c8\ub2e4.\")\n            return\n        }\n        db.transaction(function(tx) {\n            tx.executeSql(\"INSERT INTO records (text1, text2) VALUES (?, ?)\", &#91;t1, t2])\n        })\n        input1.text = \"\"\n        input2.text = \"\"\n        loadData()\n    }\n\n    \/\/ \uc120\ud0dd\ub41c \ub808\ucf54\ub4dc \uc0ad\uc81c\n    \/\/ Delete selected record\n    function deleteSelected() {\n        if (selectedId === -1) return\n        db.transaction(function(tx) {\n            tx.executeSql(\"DELETE FROM records WHERE id = ?\", &#91;selectedId])\n        })\n        loadData()\n    }\n\n\n    \/\/ DB\uc5d0 \ubaa8\ub4e0 \ub370\uc774\ud130 \uc0ad\uc81c\n    \/\/ Delete all data in DB\n    function deleteAllData() {\n        db.transaction(function(tx) {\n            tx.executeSql(\"DELETE FROM records\")\n        })\n        loadData()\n    }\n\n    ColumnLayout {\n        anchors.centerIn: parent\n        spacing: 12\n        width: 300\n\n\n        \/\/ \ub9ac\uc2a4\ud2b8 \ubdf0 \/ List View\n        Rectangle {\n            Layout.fillWidth: true\n            height: 250\n            color: \"white\"\n            border.color: \"#B0B0B0\"\n            radius: 4\n\n            ListView {\n                id: listView\n                \/\/ \ubd80\ubaa8 Reactangle\ud06c\uae30\uc640 \uac19\uac8c \uc124\uc815\n                \/\/ Set the size to be the same as the parent Reactangle\n                anchors.fill: parent\n                \/\/ \ubd80\ubaa8 Rectangle\uc758 \uacbd\uacc4 \uc548\ucabd\uc73c\ub85c 4px \uc5ec\uc720\n                \/\/ Rectangle\ud14c\ub450\ub9ac\uac00 \uc548\ubcf4\uc774\uae30\ub54c\ubb38\uc5d0\n                \/\/ 4px margin inside the parent Rectangle's border\n                \/\/ Because the Rectangle border is not visibl\n                anchors.margins: 4\n                clip: true\n                model: ListModel { id: listModel }\n                interactive: true\n                highlightFollowsCurrentItem: true\n                currentIndex: -1\n\n                delegate: Rectangle {\n                    id: delegateRect\n                    height: 36\n                    width: listView.width\n                    \/\/anchors.fill: parent\n                    \/\/anchors.margins: 6\n                    \/\/anchors.left: parent.left\n                    \/\/anchors.right: parent.right\n\n                    \/\/ \ub808\ucf54\ub4dc\uc0c9 \ubcc0\uacbd \/ Change record color\n                    color: listView.currentIndex === index ? \"#D0E6FF\" : (index % 2 === 0 ? \"#FFFFFF\" : \"#FFFFFF\")\n\n                    \/\/ -- \uc904\ubb34\ub2ac \ud615\ud0dc \uc801\uc6a9 \/ Apply striped shape\n                    \/\/color: listView.currentIndex === index ? \"#D0E6FF\" : (index % 2 === 0 ? \"#F9F9F9\" : \"#FFFFFF\")\n\n                    Row {\n                        anchors.fill: parent\n                        anchors.margins: 6\n                        spacing: 10\n                        Text { text: text1; font.pixelSize: 14; color: \"black\" }\n                        Text { text: text2; font.pixelSize: 14; color: \"gray\" }\n                    }\n\n                    MouseArea {\n                        anchors.fill: parent\n                        onClicked: {\n                            listView.currentIndex = index\n                            root.selectedId = id\n                        }\n                    }\n                }\n            }\n        }\n\n        \/\/ \uc785\ub825 \ud544\ub4dc \/ input field\n        TextField { id: input1; Layout.fillWidth: true; placeholderText: \"\ud14d\uc2a4\ud2b81 \uc785\ub825\/text1 input\" }\n        TextField { id: input2; Layout.fillWidth: true; placeholderText: \"\ud14d\uc2a4\ud2b82 \uc785\ub825\/text2 input\" }\n\n        \/\/ \ubc84\ud2bc \uc601\uc5ed \/ button area\n        RowLayout {\n            Layout.fillWidth: true\n            spacing: 10\n\n            Button {\n                text: \"\uc800\uc7a5\/Save\"\n                Layout.fillWidth: true\n                onClicked: insertData(input1.text, input2.text)\n            }\n\n            Button {\n                text: \"\uc0ad\uc81c\/Delete\"\n                Layout.fillWidth: true\n                enabled: selectedId !== -1\n                onClicked: deleteSelected()\n            }\n            Button {\n                text: \"\ubaa8\ub450\uc0ad\uc81c\/DeleteAll\"\n                Layout.fillWidth: true\n                onClicked: deleteAllData()\n            }\n        }\n    }\n}\n\n<\/code><\/pre>\n","protected":false},"excerpt":{"rendered":"<p>\ud83d\udc49\uae30\ub2a5\uc740 \ubc84\ud2bc \ud074\ub9ad\ud558\uba74 \ud14d\uc2a4\ud2b8 \uc785\ub825 2\uac1c\uc5d0 \uc785\ub825\ub41c \uc815\ubcf4\ub97c \ub85c\uceec \ub370\uc774\ud130\ubca0\uc774\uc2a4\uc5d0 \uc800\uc7a5\ud558\uace0 \ub9ac\uc2a4\ud2b8\ubdf0\uc5d0 \ud45c\uc2dc\ud574\uc90d\ub2c8\ub2e4.The function saves the information entered in the two text inputs to a local database when the button is clicked and displays it in a list view. \ud83d\udc49 QML\uc790\uccb4\uac00 \ub85c\uceec \ub370\uc774\ud130\ubca0\uc774\uc2a4 \uc5f0\ub3d9\uae30\ub2a5\uc774 \uc788\uc2b5\ub2c8\ub2e4.QML itself has a local database connection function. \ud83d\udc49\ud504\ub85c\uc81d\ud2b8\uc0dd\uc131 \ud6c4 \uc218\uc815\ud574\uc57c\ud560\uac74 [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[17,1],"tags":[],"class_list":["post-2408","post","type-post","status-publish","format-standard","hentry","category-qt","category-uncategorized","missing-thumbnail"],"_links":{"self":[{"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/posts\/2408","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/comments?post=2408"}],"version-history":[{"count":12,"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/posts\/2408\/revisions"}],"predecessor-version":[{"id":2424,"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/posts\/2408\/revisions\/2424"}],"wp:attachment":[{"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/media?parent=2408"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/categories?post=2408"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/tags?post=2408"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}