2011年9月30日 星期五

透過setGeometry設定相對於父類別的位置

在Qt提供了許多版面配置管理器 - QLayout, QGridLayout, QBoxLayout, QStackedLayout, QHBoxLayout, QVBoxLayout

這裡有一個使用Layout要注意的事情
QSizePolicy
This property holds the default layout behavior of the widget.

If there is a QLayout that manages this widget's children, the size policy specified by that layout is used. If there is no such QLayout, the result of this function is used.
意思應該是說,若已經有一個Layout在管理這一個Widget的話,那麼這一個Widget的大小就是根據這一個Layout的設定來調整。
若沒有Layout來管理這一個Widget的話,Widget才可以透過程式員自行控制。



這一些可能是我還不太會用~當視窗大小版變時,元件也同時會變大,位置變的非常不漂亮。

因此,我必需學會如何自定位置。

在QWidget可以使用setGeometry,可以設定在父類別的座標系統中,其座標位置應該在哪裡。

以下就是一個在一個Widget裡面的QPushButton設定其相對於父類別的相對位置和其大小。

#include <QApplication>
#include <QWidget>
#include <QPushButton>
#include <QLabel>

int
main (
int argc,
char *argv[]
)
{
//
// app is this program's QApplication.
// Here it is created and processes some of the command-line arguments (such as -display under X Window)
//

QApplication app (argc, argv);

//
// Create a main widget
//

QWidget *Widget = new QWidget;
Widget->setWindowTitle ("MainWidget");
Widget->resize (250, 500);

//
// Create a PushButton and the Label is "Hello World", it's parent is Widget
//

QPushButton *button = new QPushButton ("Hello World", Widget);

//
// Set the geometry of the widget relative to its parent
// This example is (20, 0) relative to it's parent
// button's size is width: 100 heigh: 50
//

// button->setGeometry (20, 0, button->sizeHint().rwidth(), button->sizeHint().rheight());
button->setGeometry (20, 0, 100, 50);

Widget->show ();

return app.exec ();
}




參考資料:

2011年9月25日 星期日

透過Qt的QRegExp翻轉檔案的開關

這次是透過QRegExp來翻轉Config.txt的特定開關,並且不改到其它的內容。
Config.txt定義在透過QRegExp分析檔案的開關

main.cpp
#include <QFile>
#include <QDebug>
#include <QTextStream>
#include <QStringList>

int main(int argc, char *argv[])
{
QFile FlagFile ("Config.txt");
QFile CopyFlagFlag ("CopyConfig.txt");
QStringList ConfigStringList;

//
// Test the Config.txt exists or not
//

if (!FlagFile.exists ()) {
qDebug () << "The flag file does not exist!!";
return -1;
}

//
// Try to open Config.txt
//

if (!FlagFile.open (QIODevice::ReadOnly)) {
qDebug () << "Can not oepn FlagFile!!";
return -1;
}

//
// Set QTextStream for Config.txt
//

QTextStream out (&FlagFile);

//
// Insert all the context into ConfigStringList
//

while (!out.atEnd ()) {
ConfigStringList << out.readLine();
}

// for (int i = 0; i < ConfigStringList.size (); i++) {
// qDebug () << ConfigStringList.at (i);
// }

//
// Try to create CopyFlagFlag.txt
//

CopyFlagFlag.open (QIODevice::WriteOnly | QIODevice::Text);

//
// Set QTextStream for CopyConfig.txt
//

QTextStream in (&CopyFlagFlag);

//
// Set the regular expressions for Flag format
//

QRegExp YesNoReg ("^(\\w+\\s*=\\s*)(YES|NO)(\\s*)$");

for (int i = 0; i < ConfigStringList.size (); i++) {

if (YesNoReg.indexIn (ConfigStringList.at (i)) != -1) {
//
// When the line match the regular expressions
//


if (YesNoReg.cap (2) == QString ("YES")) {
//qDebug () << YesNoReg.cap (1) << QString ("NO") << YesNoReg.cap (3);

//
// Invert YES to NO
//

in << YesNoReg.cap (1) << QString ("NO") << YesNoReg.cap (3);

} else {
//qDebug () << YesNoReg.cap (1) << QString ("YES") << YesNoReg.cap (3);

//
// Invert NO to YES
//

in << YesNoReg.cap (1) << QString ("YES") << YesNoReg.cap (3);

}
} else {

//
// When the line does not match the regular expressions
//


//qDebug () << ConfigStringList.at (i);
in << ConfigStringList.at (i);
}

if (i < ConfigStringList.size ()) {
in << endl;
}

}

FlagFile.close ();
CopyFlagFlag.close ();

return 0;
}


如此一開,只會改到開關,其它有幾個空白,有幾個tab完全不會動到。

參考資料:
透過QRegExp分析檔案的開關
QDataStream Class Reference

2011年9月24日 星期六

如何透過Qt讀取Unicode的檔案

今天試了一下,如何讀取Unicode的檔案,看起來,Qt都已經把它做好了,跟讀取ANSI的檔案方式沒有什麼差別。

這裡寫了一個例子,
Info.uni是一個Unicode(UTF-16)的檔案,執行這一個檔案會,
會多出一個CopyInfo.uni(UTF-16)的檔案與Info.txt(ANSI)

另外,因為,在Qt中,讀取UTF-16與ANSI的方式是一樣的,所以,
當你把Info.uni的內容改成ANSI的話,同樣程式可以work,
並且一樣會產生出CopyInfo.uni(UTF-16)的檔案與Info.txt(ANSI)

範例程式碼如下:
main.cpp
#include <QFile>
#include <QDebug>
#include <QTextStream>
#include <QStringList>

int main(int argc, char *argv[])
{
QFile UnicodeFile("Info.uni");
QFile CopyUnicodeFile("CopyInfo.uni");
QFile ANSIFile ("Info.txt");
QStringList ContainStringList;

//
// Try to open Unicode file
//

if (!UnicodeFile.open(QIODevice::ReadOnly)) {
qDebug () << "Open UnicodeFile error!!";
return -1;
}

//
// Create a QTextStream for UnicodeFile
//

QTextStream UnicodeOut (&UnicodeFile);

//
// Insert all the contain into ContainStringList
//

while (!UnicodeOut.atEnd()) {
//qDebug() << UnicodeOut.readLine();
ContainStringList << UnicodeOut.readLine();
}

UnicodeFile.close();

//
// Try to create a unicode file
//

if (!CopyUnicodeFile.open(QIODevice::WriteOnly)) {
qDebug() << "Open CopyUnicodeFile error!!";
return -1;
}

QDataStream CopyUnicodeData(&CopyUnicodeFile);

//
// Create Unicode header (FFFE) for CopyInfo.uni
//

CopyUnicodeData << (quint8) 0xFF << (quint8) 0xFE;
CopyUnicodeFile.close();

if (!CopyUnicodeFile.open(QIODevice::Append | QIODevice::Text)) {
qDebug() << "Open CopyUnicodeFile error!!";
return -1;
}

QTextStream CopyUnicodeOut (&CopyUnicodeFile);
CopyUnicodeOut.setCodec("UTF-16");

//
// Insert all the contain from ContainStringList into CopyInfo.uni (Unicode decode)
//

for (int i = 0; i < ContainStringList.size();) {
CopyUnicodeOut << ContainStringList.at(i++);
if (i < ContainStringList.size()) {
CopyUnicodeOut << endl;
}
}

CopyUnicodeFile.close();

//
// Try to create a ANSI file
//

if (!ANSIFile.open(QIODevice::WriteOnly | QIODevice::Text)) {
qDebug() << "Open ANSIFile error!!!";
return -1;
}

//
// Try to create a ANSI file
//

QTextStream ANSIOut (&ANSIFile);

//
// Insert all the contain from ContainStringList into Info.txt (ANSI decode)
//

for (int i = 0; i < ContainStringList.size();) {
ANSIOut << ContainStringList.at(i++);
if (i < ContainStringList.size()) {
ANSIOut << endl;
}
}

ANSIFile.close();

return 0;
}


參考資料:
QString Class Reference
建立一個Unicode檔案的簡單程式

2011年9月23日 星期五

透過QRegExp分析檔案的開關

今天寫了一個Qt的簡單的程式,可以用來分析一個檔案,並且把特定的位置的資料讀取出來,並且方便以後透過這一些讀取出來的設定,來做適當的動作。

假設目前有一個檔案內容如下
Config.txt
#
# This is mark
#

# Show Log or not
ShowLog = YES

# Print the User Name
PrintMyName = NO

# Show my age or not
ShowMyAge = YES # Comment for this item


程式碼如下:
main.cpp
#include <QtCore/QCoreApplication>
#include <QFile>
#include <QTextStream>
#include <QDebug>
#include <QRegExp>
#include <QStringList>

int main (int argc, char *argv[])
{
// QCoreApplication a (argc, argv);

QFile File ("Config.txt");

QString TempString;

QStringList TempStringList;

//
// Try to open file
//

if (!File.open (QIODevice::ReadOnly)) {
qDebug () << "Can Not open File!!";
return -1;
}

QTextStream out (&File);

//
// Insert all the string into TempStringList except the string start with '#' char and null line
//

QRegExp MarkReg ("^[^#].*$");
while (!out.atEnd ()) {
TempString = out.readLine ();

if (TempString.isEmpty ()) {
//
// If the line is null line, judge the next line
//

continue;
}

if (MarkReg.indexIn (TempString) != -1) {
// qDebug () << TempString;
TempStringList << TempString;
}
}

//
// Print the string in the TempStringList
//

for (int i = 0; i < TempStringList.size (); i++) {
// qDebug () << TempStringList.at (i);
}

//
// Print the string with YES flag in the end of the line
//

QRegExp YesReg ("^(\\w+)\\s*=\\s*(YES)\\s*$");
for (int i = 0;i < TempStringList.size(); i++) {
if (YesReg.indexIn (TempStringList.at (i)) != -1) {
// qDebug () << TempStringList.at (i);
// qDebug () << YesReg.cap (1);
}
}

//
// Print the string with NO flag in the end of the line
//

QRegExp NoReg ("^(\\w+)\\s*=\\s*(NO)\\s*$");
for (int i = 0; i < TempStringList.size (); i++) {
if (NoReg.indexIn (TempStringList.at (i)) != -1) {
// qDebug () << TempStringList.at (i);
// qDebug () << NoReg.cap (1);
}
}

//
// Print the string with YES or NO flag in the end of the line
//

QRegExp YesNoReg ("^(\\w+)\\s*=\\s*(YES|NO)(\\s*|\\s*#.*)$");
for (int i = 0; i < TempStringList.size (); i++) {
if (YesNoReg.indexIn(TempStringList.at (i)) != -1) {
// qDebug () << TempStringList.at (i);
qDebug () << YesNoReg.cap (1) << "is" << YesNoReg.cap (2);
}
}

// return a.exec ();
return 0;
}


參考資料:
QStringList Class Reference
QTextStream Class Reference
QRegExp Class Reference

2011年9月19日 星期一

建立一個Unicode檔案的簡單程式

最近可能要開發一個對Unicode(UTF-16)處理的工具~

今天在Qt上先試了一下如何建立一個Unicode的文件程式。

#include <QtCore/QCoreApplication>
#include <QFile>
#include <QTextStream>
#include <iostream>
#include <QtCore>

int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);

QFile file("binary.txt");
file.open(QIODevice::WriteOnly);
QDataStream out(&file);
//
// Create Unicode header (FFFE)
//

out << (qint8) 0xFF << (qint8) 0xFE;
file.close();

//QFile file("test.txt");

if (file.open (QIODevice::Append | QIODevice::Text)) {

QTextStream out1(&file);
out1.setCodec ("UTF-16");
out1 << "Hello World!!";
file.close();
}

return a.exec();
}


參考資料:
Qt4 Gossip: QTextStream
QDataStream Class Reference
QTextStream Class Reference

2011年9月18日 星期日

在Makefile裡面的command line設定變數值

在Makefile裡面的格式如下所示
target : prerequisites
command


請參考nmake 簡單教學

一般來說,要設定變數,只能在Makefile的最上面的部分
在上面那一個文章的Makefile的範例裡面,就是在everything之上設定變數

但是,我現在想做的是,依不同的target設定不同的數值~也就是想把設定數值的部分擺在command裡面。但是,在nmake的環境下,我在設定完後,直接印出來,似乎沒有達到效果。

target : prerequisites
SET TEST_VALUE=YES
ECHO $(TEST_VALUE)


最後,在多方嘗試之後,發現是可以達到我的需求的,但是,有以下幾點限制
1. 在目前的Makefile的command line設定的變數,必需觸發的下一個Makefile內才能使用
2. 變數必需不能有小寫

直接看例子吧~

Hello.c
#include <stdio.h>

int
main (
)
{
printf ("Good Morning!\n");
return 0;
}


例子一:
First.makefile
all:
[tab] SET TEST_VALUE=YES
[tab] nmake /f Second.makefile all

Second.makefile
# Program, flags, etc.
ASM = cl
OBJ = Hello.obj
TARGET = Hello.exe

all: clean everything
!IFDEF TEST_VALUE
[tab]ECHO $(TEST_VALUE)
!ENDIF

everything: $(TARGET)

clean:
[tab]- del $(OBJ) $(TARGET)

.c.obj:
[tab]$(ASM) $< /Fo$@

$(TARGET): $(OBJ)
[tab]$(ASM) $(OBJ) /Fe$@


執行指令
%> nmake /f First.makefile

如此一來,就可以在command line設定變數了,並且可以使用了。

但是,這樣的程式碼實在很難看~
那就用遞迴的方式,自己的Makefile呼叫自己的Makefile
Makefile
# Program, flags, etc.
ASM = cl
OBJ = Hello.obj
TARGET = Hello.exe

!IFDEF TEST_VALUE
all: clean everything
[tab]ECHO $(TEST_VALUE)
!ELSE
all:
[tab]SET TEST_VALUE=YES
[tab]$(MAKE) $@
!ENDIF

everything: $(TARGET)

clean:
[tab]- del $(OBJ) $(TARGET)

.c.obj:
[tab]$(ASM) $< /Fo$@

$(TARGET): $(OBJ)
[tab]$(ASM) $(OBJ) /Fe$@


執行指令
%> nmake

這一個Makefile會被執行兩次,在第一次的時候,TEST_VALUE變數並沒有被定義,
而第二次的時候,TEST_VALUE有被定義,如此一來,只需要一個Makefile就可以了

[2011.11.02 補充]
在make裡面,可以在target裡另外指定變數的值
foo = abc

all: foo = xyz
all:
[tab]echo $(foo)

這個時候的foo的值為xyz
以下的語法也提供相同的功能
all: override foo = xyz
all: export foo =xyz

但是,這個方法,似乎只能在linux下,正統的make下使用~
nmake並不支援這個語法~

參考資料:
Makefile 語法簡介

2011年9月5日 星期一

把exe與需要用到的DLL包成一個執行檔

最近為了使用Qt寫一些小工具,在研究如何把需要用到的library(DLL)在build time的時候就包進執行檔中~
把過程寫到如何build出不需要另外建置環境的QT exe檔
果然最後,還是沒有成功~~
目前release暫時的方法就是把需要用到的DLL檔跟執行檔放在一起@@,這樣就算使用者沒有Qt的環境,也是可以執行成功的。

現在找到另一個替代方案,就是如何把已經build出來的exe與其會用到的DLL甚至其它檔案包在一個exe檔案中,並且當使用者直接點兩下,可以執行我們的應用程式~~

目前找到winrar與7z(需另外安裝7z-sfx),與另一個好用的小tool 7-Zip SFX Maker(底層應該也是用7z-sfx完成的)
另外EXE Bundle - The EXE Binder,沒有試過

winrar:
1. 嘗試把要包在一起的檔案壓縮,並設定「建立自我解壓縮檔」

2. 到「進階設定」→「自解檔選項」
一般設定→解壓縮路徑→建立於現用的資料夾
一般設定→安裝程式→解壓縮之後執行→Calc.exe
模式→暫存模式→解幫裝至暫存資料夾
模式→安靜模式→全部隱藏

就會產生一個Winrar.exe的檔案,然後,直接執行它就可以了!!

7z-sfx (手動):
1. 先到7z網站下載SFX模組

2. 在製作自動解壓縮檔,只需要用到7zr.exe 與 7zSD.sfx這兩個檔案。
如何使用sfx,在Install資料夾裡面有範例~
3. 先把要包的檔案壓成7z

4. 編譯config.txt
這是設定 SFX for installers 在執行的時候的行為,包括解壓縮時要顯示什麼標題(Title)、是否要提示使用者按下確認後進行解壓縮(BeginPrompt)、或解壓縮後要自動執行哪支程式(RunProgram)、...等等。
;!@Install@!UTF-8!
Title="Simple Calc"
BeginPrompt="Do you want to run calc?"
RunProgram="Calc.exe"
;!@InstallEnd@!

詳細使用sfx的方式可以參考7z commmand的help裡面有說明~~



5. 把7zSD.sfx、config.txt、以及 Release.7z合併成執行檔,必需要透過windows內建的copy /b來完成~
copy /b 7zS.sfx+config.txt+Release.7z Release.exe
就會產生一個Release.exe的檔案,然後,直接執行它就可以了!!

7zip 進階自解壓縮檔產生工具 (自動):

7-ZIP SFX Maker (自動):

[2011.10.09 補充]
制作安裝檔
軟體王 - Inno Setup
Inno Setup

參考資料:
[問題]請問能將EXE和DLL包在一起成為一個可執行檔嗎?
如何利用 7-zip 設定自動解壓縮並解壓縮後自動啟動程式
7z-sfx 把7z檔案 製作成自解壓縮
製作屬於自己的WinRAR自解檔
7zSfxTool3.6.1.200(7z自解壓縮設定工具) 繁體中文

2011年9月2日 星期五

用Qt Creator寫一個簡單的計算機

之前有寫過一篇文章[Qtcreator - Qt的IDE],記錄Qt Creator的初體驗~
不過,當時也只是build完Qt的demo example後,覺得用Qt可以寫成這一些程式,覺得好厲害~
當時仍然以linux的環境為主,所以,初次嘗試就到此為止。

現在的主要環境改到Windows了(但是,我還是沒有放棄linux,有時候還是會玩一下)
要寫一些視窗介面的tool,因為,我用VC IDE寫程式的經驗幾乎是0,所以,我打算還是用Qt在windows下寫程式了。