第一個qt+sqlite3程序

    目前想學習下sqlite數據庫編程。之前在開發板上運行Qt程序時,出現了只能讀數據庫,不能進行寫入的情況。在網上查得可以不使用Qt自帶的數據庫,重新編譯一個sqlite3庫,然後在Qt中使用這個庫就可以了。爲了使學習的更爲全面,報着認真敲代碼的態度,我將這個學習過程以博客的形式寫出來。對程序中可能出現的問題,儘量不留死角。同時,在後面儘量解決以前遇到的問題。

    現在開發工具如下:

    smart210開發板,linux3.0.8內核,qt4.8.6程序庫,虛擬機ubuntu12.04系統,交叉編譯器arm-linux-gcc 4.5.1。

    首先是配置下環境,qte庫在友善之臂中的光盤中已經給出,這裏我簡單說一下sqlite3的編譯。首先進入源碼目錄,執行 “./configure --help > help.txt” 命令,將幫助信息打印到help.txt文件中,打開這個文件,可看到如下說明:

Installation directories:
  --prefix=PREFIX         install architecture-independent files in PREFIX
                          [/usr/local]
System types:
  --build=BUILD     configure for building on BUILD [guessed]
  --host=HOST       cross-compile to build programs to run on HOST [BUILD]
Some influential environment variables:
  CC          C compiler command
  CFLAGS      C compiler flags
  LDFLAGS     linker flags, e.g. -L<lib dir> if you have libraries in a
              nonstandard directory <lib dir>
  LIBS        libraries to pass to the linker, e.g. -l<library>
  CPPFLAGS    (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
              you have headers in a nonstandard directory <include dir>
  CPP         C preprocessor

    這裏設置prefix(安裝目錄)、host(目標平臺)、CC(編譯器)這三個參數即可。命令 “./configure --prefix=/usr/local/arm_sqlite --host=arm-linux CC=/opt/FriendlyARM/toolschain/4.5.1/bin/arm-linux-gcc” 。然後 make,make install。

    下面開始第一個qt+sqlite3工程。

    首先建立一個Qt Widgets Application 工程,這裏命名爲1_sqlite3。在工程文件1_sqlite3.pro中添加下面兩行代碼,來指定sqlite3的庫與頭文件位置。

LIBS += -L/usr/local/arm_sqlite/lib -lsqlite3
INCLUDEPATH += /usr/local/arm_sqlite/include
    接下來創建ui界面如下。


    這裏工程要實現sqlite3的基本功能,如:創建一個表格、刪除一個表格、插入一行數據、刪除一行數據、查詢一條數據並顯示。

    首先看數據庫的打開,代碼如下。

//連接數據庫
    int ret = sqlite3_open("./test.db", &db);
    if (ret != SQLITE_OK)
    {
        fprintf(stderr, "Cannot open datebase %s\n", sqlite3_errmsg(db));
        sqlite3_close(db);
        this->close();

    }
    printf("Connect success\n");

    sqlite3_open()函數會打開一個數據庫文件,當這個文件不存在則創建。下面是創建一個表格的代碼。

void MainWindow::on_pushButton_ct_clicked()
{
    const char *sSQL = "create table users ("
                       "id integer PRIMARY KEY AUTOINCREMENT, "
                       "name varchar(40) NOT NULL, "
                       "age integer NOT NULL, "
                       "birthday datetime NOT NULL, "
                       "email varchar(40) NOT NULL);";
    //執行建表SQL
    int ret = sqlite3_exec(db, sSQL, NULL, 0, &pErrMsg);
    if (ret != SQLITE_OK)
    {
        fprintf(stderr, "SQL create error: %s\n", pErrMsg);
        sqlite3_free(pErrMsg); //be supposed
        return;
    }

    rows = 0;
    index = 0;
    printf("Datebase table creator success!!\n");
}

    使用sqlite3_exec()函數可以執行一條數據庫指令,函數有5個參數,第一個是打開的數據庫索引,第二個是要執行的語句,第三個是回調函數,當成功執行數據庫語句後就會調用這個函數,第四個是傳遞給回調函數的參數,第五個是用來存儲錯誤信息。這裏創建了一個users表格,其有5列數據,第一列爲id,設爲主鍵。創建表格成功後,將表格的行數rows,當前查詢的行號置零。接下來是插入一行數據的指令,代碼如下。

void MainWindow::on_pushButton_ic_clicked()
{
    rows++;

    QByteArray qb = QString("insert into users values"
                            "(%1, 'ws_%2', %3, '1989-5-4', '[email protected]');")
                            .arg(rows).arg(rows).arg(20+rows).toLatin1();
    const char *sSQL = qb.data();
    //執行插入數據
    int ret = sqlite3_exec(db, sSQL, NULL, 0, &pErrMsg);
    if (ret != SQLITE_OK)
    {
        fprintf(stderr, "SQL insert error: %s\n", pErrMsg);
        sqlite3_free(pErrMsg); //be supposed
        return;
    }
    ui->horizontalSlider->setMaximum(rows);
    printf("Datebase insert success!\n");
}

    這裏,將id號賦值爲行號,姓名爲"ws_行號",年齡爲"20+行號",然後剩下兩個參數固定,由於創建表格與插入數據都不需要調用回調函數,所以這裏sqlite3_exec() 函數的第三個和第四個參數分別設置爲NULL和零。接下來是查詢語句,代碼如下。

void MainWindow::on_pushButton_sp_clicked()
{
    if(index == 0)  index = 1;
    if(index > 1)   index--;
    QByteArray qb = QString("select * from users where id=%1").arg(index).toLatin1();
    const char *sSQL = qb.data();
    //執行查詢操作
    int ret = sqlite3_exec(db, sSQL, _sql_callback, ui, &pErrMsg);
    if (ret != SQLITE_OK)
    {
        fprintf(stderr, "SQL error: %s\n", pErrMsg);
        sqlite3_free(pErrMsg);
        return;
    }
    ui->horizontalSlider->setValue(index);
    printf("Datebase inquire success!!\n");
}

    這裏將id號作爲查詢條件,執行了數據庫的查詢操作,查詢的結果可以通過回調函數來讀出,如果查詢的爲多行,則回調函數會被多次順序調用。這裏的回調函數爲_sql_callback(),其中傳遞給回調函數的指針爲ui指針。下面看回調函數的定義。

int MainWindow::_sql_callback(void *p, int argc, char **argv, char **szColName)
{
    Ui::MainWindow *ui = (Ui::MainWindow*)p;
    printf("Select argc:%d\n", argc);

    ui->textEdit->clear();
    for (int i = 0; i < argc; i++)
    {
        ui->textEdit->append(QString("Property :%1, Value :%2").arg(szColName[i]).arg(argv[i]));
    }

    return 0;
}

    回調函數的參數中,p指針爲傳入的參數,即上面傳入的ui指針,使用時要先將其強制轉換。argc參數表示查詢的一行數據有多少項,szColName指向該項數據的屬性名,argv指向該項數據的值。這裏將其顯示到ui界面的textEdit控件上。下面來看刪除行的操作,代碼如下。

void MainWindow::on_pushButton_dc_clicked()
{
    if(rows > 0)  rows--;
    else{
        printf("No more row..\n");
        return;
    }

    QByteArray qb = QString("delete from users where id=%1").arg(rows).toLatin1();
    const char *sSQL = qb.data();
    //delete row
    int ret = sqlite3_exec(db, sSQL, NULL, 0, &pErrMsg);
    if (ret != SQLITE_OK)
    {
        fprintf(stderr, "SQL insert error: %s\n", pErrMsg);
        sqlite3_free(pErrMsg); //be supposed
        return;
    }
    ui->horizontalSlider->setMaximum(rows);
    printf("Datebase insert success!\n");
}

    刪除行時,調用的命令爲"delete from users where id=n",刪除一行後,應將行數減一,這裏行數是通過ui控件的horizontalSlider 來表示的。接下來是刪除表格的命令,代碼如下。

void MainWindow::on_pushButton_dt_clicked()
{
    const char *sSQL = "drop table users";

    //delete table
    int ret = sqlite3_exec(db, sSQL, NULL, 0, &pErrMsg);
    if (ret != SQLITE_OK)
    {
        fprintf(stderr, "SQL delete error: %s\n", pErrMsg);
        sqlite3_free(pErrMsg); //be supposed
        return;
    }

    rows = 0;
    index = 0;
    printf("Datebase table delete success!!\n");
}

    刪除表格的命令比較簡單,爲“drop table 表名”。最後來張在開發板上運行的圖片。



    運行時,會通過串口打印命令執行的狀態。如果啓動應用時,表格已經存在,這個時候,爲了是“查詢下一條”這個按鈕可以執行往下查詢數據的命令,應該將表格的最大行數讀出來,作爲查詢的參考條件。查詢表格行數的命令是“select count(*) from 表名”,下面是查詢表格最大行數的代碼。

int MainWindow::sql_getrows(QString table)
{
    sqlite3_stmt *stat;
    QByteArray qb = QString("select count(*) from %1").arg(table).toLatin1();
    const char *sSQL = qb.data();

    int ret = sqlite3_prepare_v2(db, sSQL, -1, &stat, 0);
    if (ret != SQLITE_OK)
    {
        fprintf(stderr, "SQL error: %s\n", "prepare_v2");
        return 0;
    }

    int count=0;
    if(sqlite3_step(stat)==SQLITE_ROW)
    {
        count=sqlite3_column_int(stat, 0);
    }
    sqlite3_finalize(stat); //perpare will lock the db, this unlock the db

    return count;
}

    整個工程文件可以在http://download.csdn.net/detail/westlor/9395502下載。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章