[QT]example5-QML-database(SQLite)

👉기능은 버튼 클릭하면 텍스트 입력 2개에 입력된 정보를 로컬 데이터베이스에 저장하고 리스트뷰에 표시해줍니다.
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.

👉 QML자체가 로컬 데이터베이스 연동기능이 있습니다.
QML itself has a local database connection function.

👉프로젝트생성 후 수정해야할건 Main.qml과 Screen01.qml,CMakeLists.txt입니다.
After creating the project, the files that need to be modified are Main.qml, Screen01.qml, and CMakeLists.txt.

👉CMakeLists.txt파일에서 Screen01.qml을 인식하도록 설정합니다.
Set the CMakeLists.txt file to recognize Screen01.qml.

👉Main.qml은 Screen01.qml을 불러오는 역할만 수행합니다.
Main.qml only performs the role of loading Screen01.qml.

👉모든 데이터처리와 앱디자인은 Screen01.qml에서 수행합니다.
All data processing and app design is performed in Screen01.qml.

1.CMakeLists.txt

✔️ 프로젝트 디렉토리내에 qml/Screen01.qml 파일을 만듭니다.
Create a file named qml/Screen01.qml in the project directory.

✔️ qml/Screen01.qml 이 코드만 추가하면 됩니다.
Just add this code to qml/Screen01.qml.


cmake_minimum_required(VERSION 3.16)

project(example5 VERSION 0.1 LANGUAGES CXX)

set(CMAKE_CXX_STANDARD_REQUIRED ON)

find_package(Qt6 REQUIRED COMPONENTS Quick)
#--
find_package(Qt6 6.5 COMPONENTS Quick REQUIRED)

qt_standard_project_setup(REQUIRES 6.8)

qt_add_executable(appexample5
    main.cpp
)

qt_add_qml_module(appexample5
    URI example5
    VERSION 1.0
    QML_FILES
        Main.qml
        qml/Screen01.qml
)

# Qt for iOS sets MACOSX_BUNDLE_GUI_IDENTIFIER automatically since Qt 6.1.
# If you are developing for iOS or macOS you should consider setting an
# explicit, fixed bundle identifier manually though.
set_target_properties(appexample5 PROPERTIES
#    MACOSX_BUNDLE_GUI_IDENTIFIER com.example.appexample5
    MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION}
    MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}
    MACOSX_BUNDLE TRUE
    WIN32_EXECUTABLE TRUE
)

target_link_libraries(appexample5
    PRIVATE Qt6::Quick
)

include(GNUInstallDirs)
install(TARGETS appexample5
    BUNDLE DESTINATION .
    LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
    RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
)

2.Main.qml

✔️ 볼드체 설정 된 부분의 코드만 입력하면 됩니다.
You only need to enter the code for the bolded part.

import QtQuick
import QtQuick.Controls
import QtQuick.Window

Window {
    width: 800
    height: 600
    visible: true
    title: qsTr("QML LocalStorage Example")

    Loader {
        anchors.fill: parent
        source: "qml/Screen01.qml"  // 로컬 QML 파일 로드 / Local QML file load
    }
}

3.qml/Screen01.qml

✔️여기서 데이터 입력, 수정, 삭제를 처리합니다.
This is where you enter, edit, and delete data.

import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import QtQuick.LocalStorage

Rectangle {
    id: root
    width: 800
    height: 600
    color: "#EAEAEA"

    property var db
    property int selectedId: -1  // 선택된 레코드 ID / Seclected Record ID

    Component.onCompleted: {
        db = LocalStorage.openDatabaseSync("ExampleLocalDB", "1.0", "Local DB Example", 1000000)
        db.transaction(function(tx) {
            tx.executeSql("CREATE TABLE IF NOT EXISTS records(id INTEGER PRIMARY KEY AUTOINCREMENT, text1 TEXT, text2 TEXT)")
        })
        loadData()
    }

    // DB에서 데이터 불러오기
    // Retrieving data from DB
    function loadData() {
        db.transaction(function(tx) {
            const rs = tx.executeSql("SELECT * FROM records ORDER BY id DESC")
            listModel.clear()
            for (let i = 0; i < rs.rows.length; i++) {
                listModel.append({
                    id: rs.rows.item(i).id,
                    text1: rs.rows.item(i).text1,
                    text2: rs.rows.item(i).text2
                })
            }
            selectedId = -1
        })
    }

    // DB에 새 데이터 추가
    // Add new data to DB
    function insertData(t1, t2) {
        if (t1.trim() === "" || t2.trim() === "") {
            console.log("입력값이 비어 있습니다.")
            return
        }
        db.transaction(function(tx) {
            tx.executeSql("INSERT INTO records (text1, text2) VALUES (?, ?)", [t1, t2])
        })
        input1.text = ""
        input2.text = ""
        loadData()
    }

    // 선택된 레코드 삭제
    // Delete selected record
    function deleteSelected() {
        if (selectedId === -1) return
        db.transaction(function(tx) {
            tx.executeSql("DELETE FROM records WHERE id = ?", [selectedId])
        })
        loadData()
    }


    // DB에 모든 데이터 삭제
    // Delete all data in DB
    function deleteAllData() {
        db.transaction(function(tx) {
            tx.executeSql("DELETE FROM records")
        })
        loadData()
    }

    ColumnLayout {
        anchors.centerIn: parent
        spacing: 12
        width: 300


        // 리스트 뷰 / List View
        Rectangle {
            Layout.fillWidth: true
            height: 250
            color: "white"
            border.color: "#B0B0B0"
            radius: 4

            ListView {
                id: listView
                // 부모 Reactangle크기와 같게 설정
                // Set the size to be the same as the parent Reactangle
                anchors.fill: parent
                // 부모 Rectangle의 경계 안쪽으로 4px 여유
                // Rectangle테두리가 안보이기때문에
                // 4px margin inside the parent Rectangle's border
                // Because the Rectangle border is not visibl
                anchors.margins: 4
                clip: true
                model: ListModel { id: listModel }
                interactive: true
                highlightFollowsCurrentItem: true
                currentIndex: -1

                delegate: Rectangle {
                    id: delegateRect
                    height: 36
                    width: listView.width
                    //anchors.fill: parent
                    //anchors.margins: 6
                    //anchors.left: parent.left
                    //anchors.right: parent.right

                    // 레코드색 변경 / Change record color
                    color: listView.currentIndex === index ? "#D0E6FF" : (index % 2 === 0 ? "#FFFFFF" : "#FFFFFF")

                    // -- 줄무늬 형태 적용 / Apply striped shape
                    //color: listView.currentIndex === index ? "#D0E6FF" : (index % 2 === 0 ? "#F9F9F9" : "#FFFFFF")

                    Row {
                        anchors.fill: parent
                        anchors.margins: 6
                        spacing: 10
                        Text { text: text1; font.pixelSize: 14; color: "black" }
                        Text { text: text2; font.pixelSize: 14; color: "gray" }
                    }

                    MouseArea {
                        anchors.fill: parent
                        onClicked: {
                            listView.currentIndex = index
                            root.selectedId = id
                        }
                    }
                }
            }
        }

        // 입력 필드 / input field
        TextField { id: input1; Layout.fillWidth: true; placeholderText: "텍스트1 입력/text1 input" }
        TextField { id: input2; Layout.fillWidth: true; placeholderText: "텍스트2 입력/text2 input" }

        // 버튼 영역 / button area
        RowLayout {
            Layout.fillWidth: true
            spacing: 10

            Button {
                text: "저장/Save"
                Layout.fillWidth: true
                onClicked: insertData(input1.text, input2.text)
            }

            Button {
                text: "삭제/Delete"
                Layout.fillWidth: true
                enabled: selectedId !== -1
                onClicked: deleteSelected()
            }
            Button {
                text: "모두삭제/DeleteAll"
                Layout.fillWidth: true
                onClicked: deleteAllData()
            }
        }
    }
}

Leave a Reply