2015年12月1日 星期二

[Qt] Unicode / UTF8 / Big5 轉碼 QTextCodec 各種轉換相關

在寫Qt時候遇到問題實在搞太久了,把他記錄起來以免忘記!

1.不同system的locale會不同(中文windows vs 英文windows),因此搭配

QTextCodec::setCodecForLocale會有所不同,toLocal8bit()亦同

2.Latin1 其實就是ISO 8859-1

3.toLocal8bit()會因為locale而有所不同:

QTextCodec::setCodecForLocale(QTextCodec::codecForName("UTF-8"));

通常會有所不同,但如果是填utf8的話就跟.toUtf8()是一樣的功能囉!

4.QString內部就是Unicode編碼(最大相容於各系統),因此如果要從QString取出東西,通常都會使

用fromUnicode()

--------------------------------------------------------------------------------------------------------------------------

使用QString -->UTF8 則使用toUtf8()即可

使用QString -->Big5 (中文系統) 使用toLocal8bit()即可

使用QString -->Big5(英文系統)   ???? 翻遍網路都沒有找到,這個問題搞了兩天,終於....

使用系統: Windows POS Ready 2009 English version 2 SP3

使用語言: Qt(類C)

首先,必須要了解的是一個中文 =  兩組碼 ,一個英文 = 一組碼,如果要中英混合的話呢?

這邊我利用toUtf8()來分析length判斷目前字元是中文還是英文

(先用QString的mid()切割每一個字元)

中文的解決方法比較麻煩,英文則相較簡單。

  //英文or符號
 QString str2 = str_Trans.mid(i,1);
 QByteArray byte_array = str2.toLatin1();

 unsigned char command_english[str2.length()];
 memcpy(command_english,byte_array,str2.length());

透過toLatin1()就可以把QString轉為QByteArray,再用memcpy copy進去就可以囉!


中文:

 QTextCodec *codec = QTextCodec::codecForName("Big5");
 QByteArray b_array = codec->fromUnicode(str_Trans);

 unsigned char command_chinese[4];
 memcpy(command_chinese,b_array,4);

 for(int i = 0 ; i< sizeof(b_array); i++)
{
     int tmp = (int)command_chinese[i];
     qDebug()<<tmp;
}

透過codec的fromUnicode來轉碼,轉完就變成QByteArray,一樣透過memcpy copy

這邊如果run到沒有安裝Qt的系統(或電腦)一下就會Crash,why ??

一開始上網查,結果查到都是qcncodec4.dll (這是給簡體字的GBK,GB....),繁體必須用

qtwcodec4.dll,放進去創建的Plugins/Codecs裡面,結果!!還是Crash!!

後來把lib檔(.a)跟dll檔(.dll)整個資料夾都Copy進去以後就可以了~



















至於要放在哪邊呢? 放在你的.exe檔同一個資料夾即可


*********************************************************************************

不要再相信網路上加上

QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF-8"));
QTextCodec::setCodecForLocale(QTextCodec::codecForName("UTF-8"));
QTextCodec::setCodecForTr(QTextCodec::codecForName("UTF-8"));

類似這種(UTF-8換GBK,GB2312之類的)

就可以跑這種奇怪的解法,好好去了解這些編碼才是實際。

Unicode可以容納最多編碼方式

UTF-8則是unicode的一種表現方式

Latin1是歐美編碼

Big5是繁中

簡體則有許多GBK,GB2312...之類的

CSDN上這篇 也解釋得不錯,可以參考看看

希望下一個遇到Unicode to Big5的人可以順利解決

2015年11月17日 星期二

[Qt] FTP續傳功能

FTP續傳功能主要分為 上傳 / 下載

在開始看續傳功能之前必須要先了解,FTP有所謂的"原生指令"(Raw Command)

Raw Command包括:

TYPE - set transfer type
      TYPE I - image (binary data)
PASV - enter passive mode
PORT - open a data port
    PORT a1,a2,a3,a4,p1,p2
SIZE - return the size of a file
REST - Sets the point at which a file transfer should start
    REST position
RETR - Begins transmission of a file from the remote host.
    RETR remote-filename

Common commandsABOR - abort a file transfer
CWD - change working directory
DELE - delete a remote file
LIST - list remote files
MDTM - return the modification time of a file
MKD - make a remote directory
NLST - name list of remote directory
PASS - send password


PWD - print working directory
QUIT - terminate the connection
RETR - retrieve a remote file
RMD - remove a remote directory
RNFR - rename from
RNTO - rename to
SITE - site-specific commands

STOR - store a file on the remote host

USER - send username
Less common commandsACCT* - send account information
APPE - append to a remote file
CDUP - CWD to the parent of the current directory
HELP - return help on using the server
MODE - set transfer mode
NOOP - do nothing
REIN* - reinitialize the connection
STAT - return server status
STOU - store a file uniquely
STRU - set file transfer structure
SYST - return system type


每一個Command各自代表其中一個意思,而續傳只需要其中五個指令而已

(上傳)
1、rawCommand("TYPE I");設置傳輸數據的類型:二進制數據或ASCII
2、rawCommand("PASV");設置服務器被動接收方式。發送PASV命令後,服務器會返回自己開?的數據傳輸的端口,等待客戶端連接進行數據傳輸。返回的數據格式?:“227 Entering Passive Mode (192, 168, 2, 18, 118, 32)”,然後從返回的信息裏面或去相關的信息,ftp服務器的IP地址:192.168.2.18;ftp服務器開?的用于數據傳輸的端口:118*256 + 32 = 30240;獲得該信息後就需要建立TcpSocket的通信鏈路,連接ftp服務器。
3、rawCommand("APPE  remote-file-path");設置服務器端remote-file-path追加的方式。如果此時改文件不存在,則服務器端會創建一個。
 4、完成上述流程後,就可以打開本地文件進行讀取,並通過tcpsocket鏈路發送出去(write)。

(下載)
1、rawCommand("TYPE I");設置傳輸數據的類型:二進制數據或ASCII
2、rawCommand("PASV");設置服務器被動接收方式。發送PASV命令後,服務器會返回自己開?的數據傳輸的端口,等待客戶端連接進行數據傳輸。返回的數據格式?:“227 Entering Passive Mode (192, 168, 2, 18, 118, 32)”,然後從返回的信息裏面或去相關的信息,ftp服務器的IP地址:192.168.2.18;ftp服務器開啟的用于數據傳輸的端口:118*256 + 32 = 30240;獲得該信息後就需要建立TcpSocket的通信鏈路,連接ftp服務器。
3、rawCommand("REST  size");該命令設置ftp服務器從本地文件的哪個地方開始進行數據傳輸。
4、rawCommand("RETR  remote-file-path");開始從遠程主機傳輸文件。

        文件上傳時在設置APPE返回之後,就可以打開本地文件進行上傳;文件下載時,收到PASV的返回信息建立tcpsocket的連接後,需要建立readyRead()的信號槽,在該槽函數中實現數據的讀取。

上面是網路上找來的資料

*所謂的PASV = passive mode 被動接收模式
*size就是要從哪一點開始續傳
*端口就是Port

End(有待補充)

2015年11月4日 星期三

[Qt] Regular Expression 正規表示法 用法

正規表示法在檢查字串是否合法時,非常好用

剛好寫到就寫起來紀錄一下。

下面有三個Regular Expression

1. QRegExp regNum("\\d*");

接受所有數字(原本為\d,但C++ compiler需要再一個\ 所以就變成double \ )

2.QRegExp regCode39("[A-Z0-9+-./$%]*");

接受大寫英文,數字+-./$%,記得後面要加上* 這樣所有字元才都能檢查到,沒有*會產生邏輯上的錯誤

3.  QRegExp regCode128("[\\w\\S]*");

\w 是接受所有大小寫英文(a~z + A~Z)

\S則是接受所有特殊字元(除空白)

\s則是各種空白( \r\t\n\f)

用法很簡單,只要使用exactMatch(QString)就可以知道是否正確了

可以加速,不需要for跑很久!

END

2015年10月14日 星期三

[Qt] Read Qss file (讀取QSS檔案)

qss file內容約為:

CImageBrowseDialog {
border: none;
background-image: url(Skins/CImageBrowseDialog/Common/004-back.jpg);
}

QPushButton#previousButton {
qproperty-geometry: rect(15 656 98 70);
background-image: url(Skins/CImageBrowseDialog/Common/004-normal_25.jpg);
}

QPushButton#previousButton:pressed {
background-image: url(Skins/CImageBrowseDialog/Common/004-push_25.jpg);
}

QPushButton#previousButton:disabled {
background-image: url(Skins/CImageBrowseDialog/Common/004-gray_25.jpg);
}

QPushButton#nextButton {
qproperty-geometry: rect(907 658 97 70);
background-image: url(Skins/CImageBrowseDialog/Common/004-normal_28.jpg);
}

QPushButton#nextButton:pressed {
background-image: url(Skins/CImageBrowseDialog/Common/004-push_28.jpg);
}

QPushButton#nextButton:disabled {
background-image: url(Skins/CImageBrowseDialog/Common/004-gray_28.jpg);
}

QLabel#PreLabel
{
  border: none;
  qproperty-geometry: rect(15 720 98 40);
  color : white;
}
 
QLabel#NextLabel
{
  border: none;
  qproperty-geometry: rect(907 720 98 40);
  color : white;
}


該如何讀取呢?

在main.cpp裡面

#include <QtGui/QApplication>
#include "mainwindow.h"


int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();

    QFile file("D:\\MyCode\\Qt\\CImageBrowseDialog(QSS file)\\COMMON.QSS");
    file.open(QFile::ReadOnly);
    QString styleSheet(file.readAll());
    qDebug()<<styleSheet;
    a.setStyleSheet(styleSheet);


    return a.exec();
}


讀取路徑可以設為相對(這邊是絕對路徑)

file.readAll()就會把所有的都讀近QString當中,最後設定application的setStyleSheet()即可完成

(當然UI介面要有相對應的button/label,objectName也要相同就是了)

END

2015年10月12日 星期一

[Qt] SQLite + Qt 組合

開始要把Qt搭配SQLite了,

遇到一些問題把他先記錄起來

(*為你的project name)

1. *.pro檔案裡面需要加入

QT += sql 

2. *.h需要

 #include <QSqlDatabase>

3.使用如下:

    QSqlDatabase my_db;
    my_db = QSqlDatabase::addDatabase("QSQLITE","Qt_DB1");
    //QSLITE = 參數(driver)
    //Qt_DB1 = database名稱(請勿使用default,也就是不設,這樣使用其他的程式也呼叫default的時候會覆蓋)
    my_db.setDatabaseName("test.sqlite");
    if(my_db.open()) QMessageBox::information(0,"Ok","Connection ok");
    else QMessageBox::information(0,"Error","some error.");

(使用QMessageBox也是要include,這邊就不多贅述 // sqlite檔案使用firefox 外掛SQLite來創建)