【Qt】Qt Quick


Qt Quick http://qt.nokia.com/products/qt-quick#what-is-qt-quick

【步驟】

  • 選擇一個 Qml 的專案。
    image
  • 其他請直接參考下面的資料。

【問題】

  • Qt quick 和 Qml 有何不同。
    同事說 qt quick是利用qml做的UI+control script。(目前還是霧煞煞)
  • 如何作成執行檔?
  • 在我的系統上無法執行,

【範例】

【參考】

【Wlan】DIR-300


DIR-300 b1 是一台平價的 11n Router,也可加入 VPN 功能。摘錄一下重點,當做參考

【參考】

【Qt】DebugView and qInstallMsgHandler


【目的】

  • 將 qDebug() 導入 DebugView。
  • 以下提供使用官方 API (OutputDebugString) 配合 qInstallMsgHandler 輸出到 DebugView 的方式。

【環境】

【說明】

先由一些資料建立觀念

  • 使用 qDebug() 時可以將 DebugView 打開看看,有時輸出訊息會直接導到 DebugView。
    左圖紅色框第二個為DebugView打開前, Application Output還可以看到訊息。
    第三個是DebugView 打開後,只會看到下面訊息,表示訊息已被導到 DebugView。
    Cannot retrieve debugging output!
    image   image
  • OutputDebugString (基本程式 main.cpp)
    • 官方輸出到 DebugView
      在user-space就是呼叫 OutputDebugString ,
      而kernel-space就是呼叫DbgPrint。以下列出主要程式。
      #include <QtGui/QApplication>
      #include "dialog.h"
      #include <windows.h>
      int main(int argc, char *argv[])
      {
          QApplication a(argc, argv);
          OutputDebugString(L"Echo Message to DebugView");
          Dialog w;
          w.show();
          return a.exec();
      }
    • 結果一樣可以在 DebugView 可以看到
      image
  • qInstallMsgHandler
    • qInstallMsgHandler 的用法類似下面,可以自己指定輸出的方式,
      不過卻卻無法輸出到 DebugView。
      #include <QtGui/QApplication>
      #include "dialog.h"
      #include <qDebug>
      
      void myMessageOutput(QtMsgType type, const char *msg)
       {
           switch (type) {
           case QtDebugMsg:
               fprintf(stderr, "Debug: %s\n", msg);
               break;
           case QtWarningMsg:
               fprintf(stderr, "Warning: %s\n", msg);
               break;
           case QtCriticalMsg:
               fprintf(stderr, "Critical: %s\n", msg);
               break;
           case QtFatalMsg:
               fprintf(stderr, "Fatal: %s\n", msg);
               abort();
           }
       }
      
      int main(int argc, char *argv[])
      {
          qInstallMsgHandler(myMessageOutput);
          QApplication a(argc, argv);
          Dialog w;
          w.show();
          qDebug("Dialog is shown");
          return a.exec();
      }
    • 要解決這個問題,需要修改讓訊息可輸出到 DebugView
      #include <QtGui/QApplication>
      #include "dialog.h"
      #include <qDebug>
      #include <windows.h>
      
      void myMessageOutput(QtMsgType type, const char *msg)
       {
          char str[255];
          switch (type) {
           case QtDebugMsg:
               sprintf(str, "Debug: %s", msg);
               break;
           case QtWarningMsg:
               sprintf(str, "Warning: %s", msg);
               break;
           case QtCriticalMsg:
               sprintf(str, "Critical: %s", msg);
               break;
           case QtFatalMsg:
               sprintf(str, "Fatal: %s", msg);
               abort();
           default:
               sprintf(str, "Unknown: %s", msg);
           }
          OutputDebugStringA(str);
       }
      
      int main(int argc, char *argv[])
      {
          qInstallMsgHandler(myMessageOutput);
          QApplication a(argc, argv);
          Dialog w;
          w.show();
          qDebug("Dialog is shown");
          qWarning("Dialog is shown");
          qCritical("Dialog is shown");
          //qFatal("Dialog is shown");
          return a.exec();
      }
    • 目前問題
  • 延伸到 Linux 平台
    • 如果要將訊息輸出到 syslog,先看一下基本用法
      #incluse <syslog.h>
      main(int argc,char *argv[]){
        char *str = "test";
        openlog(argv[0],LOG_PID,LOG_USER);
        syslog(LOG_INFO,"%s\n",str);
        closelog();
      }
    • 通常會寫成一個巨集比較方便
      #ifndef NDEBUG
      #define printd(msg, args...) \
        do { \
          openlog("[Log]",LOG_PID,LOG_USER); \
          syslog(LOG_INFO, msg, ##args); \
          closelog(); \
        }while(0)
      #else
      #define printd(msg, args...)    do { } while(0)
      #endif
    • 所以 myMessageOutput 可以改成如此
      void myMessageOutput(QtMsgType type, const char *msg)
      {
          openlog(argv[0],LOG_PID,LOG_USER);
          switch (type) {
              case QtDebugMsg:
                  syslog(LOG_INFO,"Debug   : %s\n",str);
                  break;
              case QtWarningMsg:
                  syslog(LOG_INFO,"Warning : %s\n",str);
                  break;
              case QtCriticalMsg:
                  syslog(LOG_INFO,"Critical: %s\n",str);
                  break;
              case QtFatalMsg:
                  syslog(LOG_INFO,"Fatal   : %s\n",str);
                  //abort();
              }
          closelog();
      }
    • 和 Windows平台的DebugView 作整合,目前的想法是透過 ifdefine 控制, 目前程式碼先省略。
  • 嘗試修改讓訊息輸出到 檔案
    直接將 Debug message 輸出到檔案也是一個不錯的方式 myMessageOutput 可以寫成這樣。
    請注意 fclose() 要放在 if 裡面,表示開檔成功才作關檔動作。
    const char* logfile = "/var/log/log.txt";
    void myMessageOutput(QtMsgType type, const char *msg)
    {
        FILE *fp = fopen(logfile, "a");
        if (fp)
        {
            switch (type) {
            case QtDebugMsg:
                fprintf(fp, "Debug   : %s\n", msg);
                break;
            case QtWarningMsg:
                fprintf(fp, "Warning : %s\n", msg);
                break;
            case QtCriticalMsg:
                fprintf(fp, "Critical: %s\n", msg);
                break;
            case QtFatalMsg:
                fprintf(fp, "Fatal   : %s\n", msg);
                //abort();
            }
            fclose(fp);
        }
    }
  • 輸出到Kiwi Syslog Server
    如果使用 busybox 的話建議直接啟用將 –R 參數將訊息往遠端機器丟,
    除非特殊需求否則不需自己調用 socket 。
    [參考] BusyBox - The Swiss Army Knife of Embedded Linux
    http://www.busybox.net/downloads/BusyBox.html
    busybox syslogd -R 192.168.1.1:601

【想法】

  • 其實調用 qDebug/qWarning/qCritical/qFatal 對除錯而言,幫助並不大,要做的應該是將要做的事按照
    Init/Process/Close … 作分類會比較好。

【參考】

【Google】Chrome


【目的】

  • 研究 Google Chrome 的書籤(Bookmarks)與歷史記錄(History)。

【環境】

【說明】

  1. Chrome 將使用者資料以 Sqlite/Json 的格式存在下面資料夾
    C:\Users\[User Name]\AppData\Local\Google\Chrome\User Data\Default
  2. History (歷史記錄),利用 Sqliteman 打開 History這檔案,其中的
    1. urls 代表造訪過的 url。
      以其中一筆資料為例,由前兩筆就可看出造訪資料。
      1. id: 編號 (ex. 2 )
      2. url: 網址 (ex.http://www.google.com.tw/search)
      3. title: 網址抬頭 (ex.MegaTouch Framework - Google 搜尋)
      4. visit_count: 造訪次數
      5. 以下省略
        image
    2. keyword_search_terms
      1. keyword_id: 編號 (ex.2 , [問題]為目前看到的都是 2)
      2. url_id: 關連到 urls 表格的 id (ex. 1815 代表關連到 urls 裡面 id=1815 的搜尋結果資料)
      3. lower_term: 使用者所搜尋過的字串,小寫方式(ex. sqlite 資料庫, s 會變小寫)
      4. term: 使用者所搜尋過的字串,大小寫不變(ex. Sqlite 資料庫)
        image
  3. Bookmarks(書籤)
    1. 採用的是JSON格式,請直接將內容貼到 JSON Editor(http://braincast.nl/samples/jsoneditor/)
      就可看到比較方便越讀的內容。
       image
  4. Cookies
    1. Cookies 資料,此處不詳述。
      image
  5. Thumbnails(縮圖)
    1. thumbnails 提供類似 Speed Dail 的功能
      1. url_id
      2. boring_score
      3. good_clipping
      4. at_top
      5. last_updated
      6. data: 採用 sqlite blob 格式,裡面的就是 直接將 png 格式圖檔存在資料庫。
        image
      7. 如果要直接編修圖形,直接 Double-Click {blob} 後就會出現下面視窗,使用 Open/Save 就可編輯。
        image 

【問題】

  1. 如何找出 Thumbnails 裡面的網址與說明。
  2. 如何將圖檔存入與讀出 Sqlite
    A: sqlite处理BLOB数据 http://sqlite.com.cn/bbs/topicdisp.asp?tid=34&topage=179

【參考】

【Qt】Sqlite


首先複習一下 sqlite shell 的用法,驗證幾個重點

【Sqlite】

  • Sqlite 支援的資料型態
    • TEXT
    • NUMERIC
    • INTEGER
    • REAL
    • NONE(BOOL)
  • 基本操作,假設我們要建立一個像下面一樣的資料庫來記錄姓名,
    中間混合繁體中文(Big5所謂的許功蓋問題),英文(Chen)與俄文(Ира)。
      firstname(名) lastname(姓)
    第一筆資料 功蓋
    第二筆資料 Ира Chen
  • 首先進入sqlite ,先建立名為 p.db 的資料庫來儲存上面資料。
    $ sqlite3 p.db
    SQLite version 3.6.16
    Enter ".help" for instructions
    Enter SQL statements terminated with a ";"
  • create: 先建立資料表,一個資料庫裡面可以有許多資料表。
    sqlite> create table person (firstname varchar(20), lastname varchar(20));
  • 列出資料表,確定上個動作已經是成功的。
    sqlite> .table
    person
  • 列出 schema,確認所建立的欄位。 
    sqlite> .schema person
    CREATE TABLE person (firstname varchar(20), lastname varchar(20));
  • insert: 開始新增我們所需要的那兩筆資料。
    sqlite> insert into person values('功蓋', '許');
    sqlite> insert into person values('Ира', 'Chen');
  • select: 查詢rowid
    sqlite> select rowid from person;
    1
    2
  • select: 查詢資料,確定新增兩筆資料成功。
    sqlite> select * from person;
    功蓋|許
    ира|Chen
  • where: 利用 select 配合 where 查詢符合姓為 Chen 這個人的資料。
    sqlite> select * from person where lastname='Chen';
    ира|Chen
  • 建立視圖,可區別一般使用者或管理者所要看到的資料。
    sqlite> create view pv as select lastname from person;
    sqlite> select * from pv;
    許
    Chen
  • 更新,把 Ира Chen 改成 May Chen。 
    sqlite> 
    sqlite> update person set firstname='May' where lastname='Chen';
    sqlite> select * from person;
    功蓋|許
    May|Chen
  • 刪除,把 第二筆資料刪除,這樣就只剩下 許功蓋 這個人
    sqlite> delete from person where lastname='Chen';
    sqlite> select * from person;
    功蓋|許
  • 新增欄位,假設我們新增加一個 id 的欄位
    sqlite> alter table person add id integer;
    sqlite>  .schema person
    CREATE TABLE person(firstname varchar(20), lastname varchar(20), id integer);
  • 刪除欄位
    目前好像不支援。 (http://www.sqlite.org/lang_altertable.html)
    解決想法是整個 table 刪掉並重建欄位。
    (1) 更名原始資料表,如由 table 改成 table_tmp  (2) 建立新Table,新Table是不包含要刪除的欄位的。
    (3) 由備份的 table_tmp 整個倒入新 table,不包含要拿掉欄位的資料。
  • 更名欄位
    目前好像不支援。 解決方式同上。只是在建立新table時,作欄位更名的動作。
  • 更名資料表,將 person 資料表改名成 p 資料表。 
    sqlite> alter table person remane to p;
    sqlite> .schema p
    CREATE TABLE "p"(firstname varchar(20), lastname varchar(20), id integer);
  • 資料庫匯出(未驗證)
    $sqlite3 p.db “.dump” > p.sql
  • 資料庫匯入(未驗證)
    $ sqlite3 p.db < p.sql
  • 離開
    sqlite> .quit 
    $ 

【Sqliteman】

  • 除了 sqlite shell 以外,還可以使用一套據說是 QT 寫的 sqliteman http://sqliteman.com/ 來觀察剛剛的結果。運行結果如下。可以看到 Tables 與 Views。
    image
  • 有時作者並不一定會在現行版本發行Windows版本,就要往回找之前發行的版本。
    下載網址 http://sourceforge.net/projects/sqliteman/files/image

【C】

在 C 的使用 (目前沒有用C特別處理 Unicode的問題,參考 http://evanjones.ca/unicode-in-c.html)

  1. 安裝套件
    $ apt-get install libsqlite3-dev
  2. 程式碼( 存成 p.c )
    #include <stdio.h> 
    #include <sqlite3.h>
     
    static int callback(void *NotUsed, int argc, char **argv, char **azColName){ 
    int i; 
    for(i=0; i<argc; i++){ 
    printf("%s = %s\n", azColName[i], argv[i] ? argv[i] : "NULL"); 
    } 
    printf("\n"); 
    return 0; 
    } 
     
    int main(int argc, char **argv){ 
    sqlite3 *db; 
    char *zErrMsg = 0; 
    int rc; 
     
    if( argc!=3 ){ 
    fprintf(stderr, "Usage: %s DATABASE SQL-STATEMENT\n", argv[0]); 
    return 1;
    } 
    rc = sqlite3_open(argv[1], &db); 
    if( rc ){ 
    fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db)); 
    sqlite3_close(db); 
    return 1; 
    } 
    rc = sqlite3_exec(db, argv[2], callback, 0, &zErrMsg); 
    if( rc!=SQLITE_OK ){ 
    fprintf(stderr, "SQL error: %s\n", zErrMsg); 
    sqlite3_free(zErrMsg); 
    } 
    sqlite3_close(db); 
    return 0; 
    }
  3. 編譯(注意要加 –lsqlite3)
    $ gcc -o p p.c –lsqlite3 
  4. 執行
    $./p p.db "select * from person;"
    firstname = 功蓋
    lastname = 許
    id = NULL
    
    firstname = ира
    lastname = Chen
    id = NULL

【Qt】
配合QT的使用。其中需要注意的是,Sqlite內部編碼為 unicode, 而Qt 我們指定為 UTF-8。
Qt 寫入 Sqlite 需先將內容轉換成 Unicode,而Qt 讀取Sqlite時不需要,因 Qt 會自行偵測。
以下只擷取出重點程式碼。

  1. 記得載入 QtSql module。
    image
  2. dialog.h ( include  部分)
    #include <QtSql>
    #include <QTableView>
    #include <QMessageBox>
  3. dialog.cpp
    bool Dialog::SqliteTest()
    {
    
        QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
        db.setDatabaseName("database.dat");
        if (!db.open())
        {
            QMessageBox::warning(0, QObject::tr("Database Error"),
                                 db.lastError().text());
            return false;
        }
        QSqlQuery rs(db);
        rs.exec("CREATE TABLE person (firstname varchar(20), lastname varchar(20))");
        QByteArray strSql("insert into person(firstname,lastname) \
                       values('Ира', 'Chen')");
        QTextCodec *codec = QTextCodec::codecForName("UTF-8");
        QString string = codec->toUnicode(strSql);
        rs.exec(string);
    
        QSqlQueryModel *model = new QSqlQueryModel;
        model->setQuery("SELECT * FROM person");
        model->setHeaderData(0, Qt::Horizontal, "firstname");
        model->setHeaderData(1, Qt::Horizontal, "lastname");
    
        QTableView *view = new QTableView;
        view->setWindowTitle("QSqlQueryModel");
        view->setModel(model);
        view->show();
    
        db.close();
    }
  4. 執行結果
    image

【參考】

【Qt】SQLCipher


【目的】

  • 加密 Sqlite 資料。

【方法】

方法一

  1. 調用 C 的crypto libraries 將原始資料(如 Base64Encoder)加密。
  2. 將加密後的資料存入 Sqlite。
  3. 缺點就是資料量會變大,讀取速度變慢。

方法二

  1. 另一個方法據說原作者留有設定帳號密碼的function,不過這部分還得測試。
    且這部分須更改sqlite原始碼,較不適用已有Sqlite的現成平台。

方法三

  1. 利用現成的SQLCipher達到加密效果。此方法也適用用Xcode開發的程式。
  2. SQLCipher 利用的是 OpenSSL,AES-256…格式作加密。
  3. SQLCipher使用MIT-style license,這是一種比較寬鬆的版權協定。

【程式】

  • tbd

【參考】

【其它參考】

參考價值不大。

 

Ed32. Copyright 2008 All Rights Reserved Revolution Two Church theme by Brian Gardner Converted into Blogger Template by Bloganol dot com