[QT]example6-C++,QML-database(SQLite)

๐Ÿ‘‰ QML์€ ๋””์ž์ธ์„ ๋‹ด๋‹นํ•˜๊ณ  C++์ด ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ๋ฅผ ๋‹ด๋‹นํ•ฉ๋‹ˆ๋‹ค.
QML handles the design and C++ handles the data processing.

๐Ÿ‘‰ qt_add_excutableํ•จ์ˆ˜๋Š” exeํŒŒ์ผ์„ ๋งŒ๋“ค๋•Œ ํ•„์š”ํ•œ cppํŒŒ์ผ ๋ฆฌ์ŠคํŠธ์ž…๋‹ˆ๋‹ค.
The qt_add_executable function is a list of cpp files required when creating an exe file.

1.CMakeLists.txt

cmake_minimum_required(VERSION 3.16)

project(example6 VERSION 0.1 LANGUAGES CXX)

set(CMAKE_CXX_STANDARD_REQUIRED ON)

find_package(Qt6 REQUIRED COMPONENTS Quick)

#--sqlite
find_package(Qt6 REQUIRED COMPONENTS Quick Sql)


qt_standard_project_setup(REQUIRES 6.8)

#-- making .exe file list
qt_add_executable(appexample6
    main.cpp
    #--sqlite
    databasemanager.cpp
)

qt_add_qml_module(appexample6
    URI example6
    VERSION 1.0
    QML_FILES
        Main.qml
        #-- ์ถ”๊ฐ€/Add
        qml/Screen01.qml
        SOURCES Databasemanager.h Databasemanager.cpp
)

# 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(appexample6 PROPERTIES
#    MACOSX_BUNDLE_GUI_IDENTIFIER com.example.appexample6
    MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION}
    MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}
    MACOSX_BUNDLE TRUE
    WIN32_EXECUTABLE TRUE
)
#-- sqlite
target_link_libraries(appexample6
    PRIVATE Qt6::Quick Qt6::Sql
)

target_link_libraries(appexample6
    PRIVATE Qt6::Quick
)

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

2.databasemanager.h

#ifndef DATABASEMANAGER_H
#define DATABASEMANAGER_H

#include <QObject>
#include <QSqlDatabase>
#include <QSqlQuery>
#include <QSqlError>
#include <QVariantList>
#include <QDebug>

class DatabaseManager : public QObject {
    Q_OBJECT
public:
    explicit DatabaseManager(QObject *parent = nullptr);
    Q_INVOKABLE bool insertData(const QString &text1, const QString &text2);
    Q_INVOKABLE QVariantList loadData();
    Q_INVOKABLE bool deleteData(int id);
    Q_INVOKABLE bool deleteAll();

private:
    QSqlDatabase db;
    void initialize();
};

#endif // DATABASEMANAGER_H

3.databasemanager.cpp

#include "DatabaseManager.h"

DatabaseManager::DatabaseManager(QObject *parent)
    : QObject(parent)
{
    db = QSqlDatabase::addDatabase("QSQLITE");
    db.setDatabaseName("localdata.db");

    if (!db.open()) {
        qWarning() << "Database open error:" << db.lastError().text();
        return;
    }

    initialize();
    qDebug() << "๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ดˆ๊ธฐํ™” ์‹คํ–‰/Run database initialization";
}

// ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ดˆ๊ธฐํ™” / database initialize
void DatabaseManager::initialize() {
    QSqlQuery query;
    query.exec("CREATE TABLE IF NOT EXISTS records ("
               "id INTEGER PRIMARY KEY AUTOINCREMENT, "
               "text1 TEXT, "
               "text2 TEXT)");
}
// ์ž…๋ ฅ / input
bool DatabaseManager::insertData(const QString &text1, const QString &text2) {
    QSqlQuery query;
    query.prepare("INSERT INTO records (text1, text2) VALUES (?, ?)");
    query.addBindValue(text1);
    query.addBindValue(text2);
    bool ok = query.exec();
    if (!ok) qWarning() << "Insert failed:" << query.lastError().text();
    return ok;
}

// ๋ฐ์ดํ„ฐ ๋กœ๋”ฉ / data loading
QVariantList DatabaseManager::loadData() {
    QVariantList list;
    QSqlQuery query("SELECT id, text1, text2 FROM records ORDER BY id DESC");
    while (query.next()) {
        QVariantMap item;
        item["id"] = query.value(0).toInt();
        item["text1"] = query.value(1).toString();
        item["text2"] = query.value(2).toString();
        list.append(item);
    }
    return list;
}
// ์‚ญ์ œ / data Delete
bool DatabaseManager::deleteData(int id) {
    QSqlQuery query;
    query.prepare("DELETE FROM records WHERE id = ?");
    query.addBindValue(id);
    bool ok = query.exec();
    if (!ok) qWarning() << "Delete failed:" << query.lastError().text();
    return ok;
}
// ๋ชจ๋‘ ์‚ญ์ œ /delete all data
bool DatabaseManager::deleteAll() {
    QSqlQuery query("DELETE FROM records");
    return query.exec();
}

4.qml/Screen01.qml

import QtQuick
import QtQuick.Controls
import QtQuick.Layouts

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

    property int selectedId: -1

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

        // ๋ฆฌ์ŠคํŠธ๋ทฐ / ListView
        Rectangle {
            Layout.fillWidth: true
            height: 250
            color: "white"
            border.color: "#B0B0B0"
            radius: 4

            ListView {
                id: listView
                anchors.fill: parent
                anchors.margins: 4
                clip: true
                model: ListModel { id: listModel }
                interactive: true
                currentIndex: -1

                delegate: Rectangle {
                    height: 36
                    width: listView.width
                    //color: listView.currentIndex === index ? "#D0E6FF" : (index % 2 === 0 ? "#FFFFFF" : "#F9F9F9")
                    color: listView.currentIndex === index ? "#D0E6FF" : (index % 2 === 0 ? "#FFFFFF" : "#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 ์ž…๋ ฅ/text input1" }
        TextField { id: input2; Layout.fillWidth: true; placeholderText: "ํ…์ŠคํŠธ2 ์ž…๋ ฅ/text input2" }

        // ๋ฒ„ํŠผ / button
        RowLayout {
            Layout.fillWidth: true
            spacing: 10

            Button {
                text: "์ €์žฅ/Save"
                Layout.fillWidth: true
                onClicked: {
                    if (input1.text.length === 0 || input2.text.length === 0)
                        return
                    DB.insertData(input1.text, input2.text)
                    refreshList()
                    input1.text = ""
                    input2.text = ""
                }
            }

            Button {
                text: "์‚ญ์ œ/Delete"
                Layout.fillWidth: true
                enabled: root.selectedId !== -1
                onClicked: {
                    DB.deleteData(root.selectedId)
                    root.selectedId = -1
                    refreshList()
                }
            }

            Button {
                text: "๋ชจ๋‘์‚ญ์ œ/Delete All"
                Layout.fillWidth: true
                onClicked: {
                    DB.deleteAll()
                    refreshList()
                }
            }
        }
    }

    // ๋ฐ์ดํ„ฐ ์ƒˆ๋กœ๊ณ ์นจ / data refresh
    function refreshList() {
        listModel.clear()
        const data = DB.loadData()
        for (let i = 0; i < data.length; i++) {
            listModel.append({
                id: data[i].id,
                text1: data[i].text1,
                text2: data[i].text2
            })
        }
    }

    Component.onCompleted: refreshList()
}

5.main.cpp

#include <QGuiApplication>
#include <QQmlApplicationEngine>

//์ฝ”๋“œ์ถ”๊ฐ€ / Add code
#include <QQmlContext>          // QML๊ณผ C++ ์—ฐ๊ฒฐ์šฉ / For connecting QML and C++
#include "DatabaseManager.h"    // database

int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);

    QQmlApplicationEngine engine;


    QObject::connect(
        &engine,
        &QQmlApplicationEngine::objectCreationFailed,
        &app,
        []() { QCoreApplication::exit(-1); },
        Qt::QueuedConnection);


    // DatabaseManager ์ธ์Šคํ„ด์Šค ์ƒ์„ฑ
    // Create a DatabaseManager instance
    static DatabaseManager dbManager;


    // QML ์ „์—ญ ์ปจํ…์ŠคํŠธ์— ๋“ฑ๋ก
    // Register in the QML global context
    engine.rootContext()->setContextProperty("DB", &dbManager);

    //
    engine.loadFromModule("example6", "Main");

    return app.exec();
}

6.main.qml

import QtQuick

Window {
    width: 640
    height: 480
    visible: true
    title: qsTr("Hello World")
    Loader {
        anchors.fill: parent
        source: "qml/Screen01.qml"  // ๋กœ์ปฌ QML ํŒŒ์ผ ๋กœ๋“œ / Local QML file load
    }
}

7.์‹คํ–‰ / run

Leave a Reply

Your email address will not be published. Required fields are marked *