顯示具有 Programming 標籤的文章。 顯示所有文章
顯示具有 Programming 標籤的文章。 顯示所有文章

BOOST 1.35.0 is out!

boost 更新了!增加了十一個新的 library。

New Libraries
* Asio:
Portable networking, including sockets, timers, hostname resolution and socket iostreams, from Chris Kohlhoff.

* Bimap:
Boost.Bimap is a bidirectional maps library for C++. With Boost.Bimap you can create associative containers in which both types can be used as key, from Matias Capeletto.

* Circular Buffer:
STL compliant container also known as ring or cyclic buffer, from Jan Gaspar.

* Function Types:
Boost.FunctionTypes provides functionality to classify, decompose and synthesize function, function pointer, function reference and pointer to member types. From Tobias Schwinger.

* Fusion:
Library for working with tuples, including various containers, algorithms, etc. From Joel de Guzman, Dan Marsden and Tobias Schwinger.

* GIL:
Generic Image Library, from Lubomir Bourdev and Hailin Jin.

* Interprocess:
Shared memory, memory mapped files, process-shared mutexes, condition variables, containers and allocators, from Ion Gaztañaga.

* Intrusive:
Intrusive containers and algorithms, from Ion Gaztañaga.

* Math/Special Functions:
A wide selection of mathematical special functions from John Maddock, Paul Bristow, Hubert Holin and Xiaogang Zhang.

* Math/Statistical Distributions:
A wide selection of univariate statistical distributions and functions that operate on them from John Maddock and Paul Bristow

* MPI:
Message Passing Interface library, for use in distributed-memory parallel application programming, from Douglas Gregor and Matthias Troyer.

* System:
Operating system support, including the diagnostics support that will be part of the C++0x standard library, from Beman Dawes.

加了不少實用的東西,看來至少可以先玩玩 ASIO 還有 MPI 看看...

Emacs Cheat Sheet

年紀大了,在寫程式的時候常常會忘記指令。做一下 cheat sheet 好了

基本指令
C-x C-c 離開
C-g 清除 command
C-u undo
C-h help

移動游標
C-f 前進
C-b 後退
C-n 下一行
C-p 上一行
C-a 開頭
C-e 結尾
C-v 下一頁
M-v 上一頁
M-< 檔案的開頭
M-> 檔案的結尾

搜尋和取代
C-s 往前搜尋
C-r 往後搜尋
M-x replace-string 替代字串

編輯
C-d 刪除下一個字元
Backspace 刪除前一個字元
M-d 刪除下一個字
C-k 刪除到行末
C-w 剪下區塊
M-w 複製區塊
C-y 貼上
C-@ 設定區塊

視窗
C-x 2 創造水平視窗
C-x 3 創造垂直視窗
C-x 0 刪除視窗
C-x 1 刪除另一個視窗
C-x o 移動到另一個視窗

Boost Libraries: Foreach

BOOST_FOREACH 是甚麼?

在 C++ 中,寫一個 iterate 一整個 sequence 的迴圈是讓人厭煩的,我們可以用 iterators,但是需要寫很多照本宣科的程式碼。或是我們可以用 std::for_each() 演算法,但是其實它也沒有省下多少功夫。相對之下,像是 Perl 之類的語言提供了內建的 "foreach" 來自動建構這樣的程序。BOOST_FOREACH 就是這類程序的 C++ 版本。它會直接幫助我們 iterates 整個 seqeuce,讓我們不用跟 iterators 奮鬥。

BOOST_FOREACH 是為了簡單易用以及有效率而設計的,他不會做動態 allocation,沒有 virtual function calls 也不用任何的 function pointers。這讓它可以產生 near-optimal 的程式碼,BOOST_FOREACH 的效率通常只跟手寫的 loop 差了幾個百分比而已。儘管 BOOST_FOREACH 是一個 macro,他的表現相當的出色。它剛好 evaluate 他的 argument 一次,讓我們不會看到有預期之外的效果。

Hello, world!

下面是一個簡單的程式,它使用了 BOOST_FOREACH 來 iterate 一個 std::string 的內容。
#include <string>
#include <iostream>
#include <boost/foreach.hpp>

int main()
{
    std::string hello( "Hello, world!" );
    
    BOOST_FOREACH( char ch, hello )
    {
        std::cout << ch;
    }

    return 0;
}
程式會 output
Hello world!
支援的類型

BOOST_FOREACH 會 iterates seqeuces,不過甚麼才會真正的組成一個 sequence?BOOST_FOREACH 是建構在 Boost.Range 之上,所以它自然會支援那些 Boost.Range 可以辨認的類型。舉例來說,我們可以用:
    * STL containers
    * arrays
    * Null-terminated strings (char and wchar_t)
    * std::pair of iterators
範例

下面是幾個使用 BOOST_FOREACH 的範例: 在 STL container 做 iterate:
std::list list_int( /*...*/ );
BOOST_FOREACH( int i, list_int )
{
    // do something with i
}
在 array 上面做 iterate with covariance (就是說 iteration variable 跟 element 的型別不完全一致)
short array_short[] = {1,2,3};
BOOST_FOREACH( int i, array_short )
{
    // The short was implicitly converted to an int
}
在 loop 中使用 return, continue 以及 break
std::deque deque_int( /*...*/ );
int i = 0;
BOOST_FOREACH( i, deque_int )
{
    if( i == 0 ) return;
    if( i == 1 ) continue;
    if( i == 2 ) break;
}
透過 reference iterate 整個 sequence,並且做變更
short array_short[] = { 1, 2, 3 };
BOOST_FOREACH( short & i, array_short )
{
    ++i;
}
// array_short contains {2,3,4} here
利用巢狀 BOOST_FOREACH iterate 一個二維 vector
std::vector<std::vector<int> > matrix_int;
BOOST_FOREACH( std::vector<int> & row, matrix_int )
    BOOST_FOREACH( int & i, row )
        ++i;

Minimum and Maximum Operators in C++

今天偶然發現的Minimum and Maximum Operators in C++。可以用以下的 code 很簡單的產生 Minimum 以及 Maximum:
max = x >? y ;
min = x <? y ;

不過要注意一下,這個是 g++ 才有的 extensions,別的 compiler 無法使用。

Boost Libraries: Format

在傳統的 C 語言當中,處理 output 的問題我們會用 printf 這個 function。藉由 printf 的格式化輸出,可以方便的做些簡單的排版輸出。等到進入了 C++ 時代,cout 取代了 printf,但是卻失去了原本好用的格式化輸出,使得有時候處理 output 會變成一件繁瑣的事情。boost::format 就是為了這個而生。

Synopsis
一個 format 物件是經由 format-string 和其後的參數建構而來,後面傳進來的參數是以 operator % 來做連接的。每一個參數都會被轉型成為 string 的型式,接著在依照 format-string 的樣子轉換成一個 string。下面是一個例子:
cout << boost::format("writing %1%,  x=%2% : %3%-th try") % "toto" % 40.23 % 50; 
     // prints "writing toto,  x=40.230 : 50-th try"

How it works
  1. 當你呼叫 format(s) 時,它將會建構一個 format 物件,並且 parse 其中的 format string 給下一個步驟使用。
  2. 接著,可能是馬上,就像
    cout << format("%2% %1%") % 36 % 77 ;
    
    或是稍後,就像
    format fmter("%2% %1%");
    fmter % 36; fmter % 77;
    
    你把變數「餵」到 format 當中,這些變數會變成所謂的 internal stream,它們的 state 是由之前的 format-string 所決定的,接著 format string 將會儲存這些結果給下一步使用。
  3. 當所有的參數都被餵進去之後,你可以把 format dump 到一個 stream 當中,或是透過 member function str() 轉成一個 string。如例子:
    // fmter was previously created and fed arguments, it can print the result :
    cout << fmter ;  
    
    // You can take the string result :
    string s  = fmter.str();
    
    // possibly several times :
    s = fmter.str( );
    
    // You can also do all steps at once :
    cout << boost::format("%2% %1%") % 36 % 77; 
    
    // using the str free function :
    string s2 = str( format("%2% %1%") % 36 % 77 );
    
    
  4. 另外,你還可以重新使用用過的 format object,來降低處理的複雜度。

Examples
  • 簡單的 output,有 re-ordering:
    cout << format("%1% %2% %3% %2% %1% \n") % "11" % "22" % "333"; // 'simple' style.
    
    將會輸出 "11 22 333 22 11 \n"
  • 更精確的格式輸出:
    cout << format("(x,y) = (%1$+5d,%2$+5d) \n") % -23 % 35;     // Posix-Printf style
    
    會輸出:"(x,y) = ( -23, +35) \n"
  • 傳統的 printf 語法,沒有 re-ordering:
    cout << format("writing %s,  x=%s : %d-th step \n") % "toto" % 40.23 % 50; 
    
    輸出:"writing toto, x=40.23 : 50-th step \n"
  • 幾種表達同樣東西的方法:
    cout << format("(x,y) = (%+5d,%+5d) \n") % -23 % 35;
    cout << format("(x,y) = (%|+5|,%|+5|) \n") % -23 % 35;
    
    cout << format("(x,y) = (%1$+5d,%2$+5d) \n") % -23 % 35;
    cout << format("(x,y) = (%|1$+5|,%|2$+5|) \n") % -23 % 35;
    
    這些都代表著:"(x,y) = ( -23, +35) \n"
  • 使用 manipulators 去修改 format-string
    format fmter("_%1$+5d_ %1$d \n");
    
    format fmter2("_%1%_ %1% \n");
    fmter2.modify_item(1, group(showpos, setw(5)) ); 
    
    cout << fmter % 101 ;
    cout << fmter2 % 101 ;
    
    都是代表著 "_ +101_ 101 \n"
  • 使用有參數的 manipulators:
    cout << format("_%1%_ %1% \n") % group(showpos, setw(5), 101);
    
    manipulators 會在每個有 %1% 的地方作用,因此會輸出 "_ +101_ +101 \n"
  • 新的 format features:"absolute tabulations",在迴圈當中相當有用,可以確定一個欄位在每一行都是輸出在同一個位置。
    for(unsigned int i=0; i < names.size(); ++i)
        cout << format("%1%, %2%, %|40t|%3%\n") % names[i] % surname[i] % tel[i];
    
    可能的輸出會如下:
    Marc-François Michel, Durand,           +33 (0) 123 456 789
    Jean, de Lattre de Tassigny,            +33 (0) 987 654 321
    
其他的部分可以在 boost format 的 document 當中看到,不過大概看過這些就可以應用了。

Boost Libraries: Timer

在寫程式的時候,我們常常會希望知道程式總共跑了多久,或是某個 function 需要執行多久,來瞭解我們的 performance。通常會使用的方法是利用 time.h 裡面的 clock() 來達到我們想要的目的,程式大概會長這樣:
#include <ctime>
#include <iostream>

using namespace std ;

int main( void ) {
   clock_t t = clock() ;
   // do something....
   cout << "The program runs " << (clock()-t)/CLK_TCK << 
   " seconds" << endl ;
   return 0 ;
}

這樣當然是沒啥不好的,不過人總是懶惰,有時候會覺得要寫那麼多行 code 是很麻煩的事情。所以就有了 boost::timer 的誕生。
Boost timer 的使用相當簡單,基本上只有三個 class。接下來就一一介紹。

Class Timer
timer 這個 class 會測量經過的時間,通常使用在程式當中一些比較繁瑣的 timing 測量方面。實做其實就是利用上面講過的 clock() function。要注意的是,timer 最多可以測量的時間大概是 596.5 小時(或是更少)。以下是一個簡單的例子:
#include <boost/timer.hpp>
#include <iostream>

using namespace std ;
using namespace boost ;

int main( void ) {
  timer t1 ;
  // do something..
  cout << t1.elapsed() << endl ;

  return 0 ;
}

如此便可以輸出 t1 這個 timer 經過的時間。

Class progress_timer
progress_timer 跟 timer 很相似,差別是在它會自動在 destruction 的時候輸出 progress_timer 所經過的時間。例子如下:
#include <boost/progress.hpp>
int main()
{
   progress_timer t;  // start timing
   // do something ...
   return 0;
}

如此程式會於結束的時候輸出如 0.06 s 之類的訊息:

Class progress_display
progress_display 這個 class 則就是傳統我們會看到的 progress bar 功能。這個只是要給人看,讓人知道這隻程式正在跑。舉例來說,如果我們想要來在 map 當中插入 element,在插入的途中想利用 progress_display 來知道進度,可以用以下的 code:
#include <boost/progress.hpp>
#include <map>
#include <iostream>

using namespace std ;
using namespace boost ;

int main( void ) {
  map big_map ;
  progress_display show_progress( 1000000 ) ;

  for ( int i = 0 ; i < 1000000 ; i++ ) {
    big_map.insert( make_pair(i,i) ) ;
    ++show_progress ;
  }

  return 0 ;
}
在大約有 70% 的 element 被插入時,progress_display 會顯示
0%   10   20   30   40   50   60   70   80   90   100%
|----|----|----|----|----|----|----|----|----|----|
************************************

google code prettify

這幾天一直在找在 blogger 上面可以讓貼程式碼比較方便的辦法,最後在 dp.SyntaxHighlightergoogle-code-prettify 之間我選擇了 google code prettify。

google-code-prettify 的使用相當簡單,首先先去下載網頁上面抓下它的 CSS 和 js 檔案,上傳到網頁空間。接著在網頁前面加上:
<link href="prettify.css" type="text/css" rel="stylesheet" />
<script type="text/javascript" src="prettify.js"></script>
其中,prettify.css 和 prettify.js 這兩個檔案必須更改正確的路徑。接著,在 body 這個 tag 加上 onload="prettyPrint()",這樣就完成了設定的動作。

當你要將某段 code 貼上時,你只要將要貼上的 code 以 <pre class="prettyprint">...</pre>包起來,就可以達到 syntax highlight 的效果。

Subversion with Apache 架設

Subversion 是一套版本控制 (Version Control) 的軟體,何謂 Version Control ?以我們寫程式的時候為例,Programmer 常常會遇到在更改程式的時候,因為種種不明因素而忘記自己改了些什麼,這時候通常都會想「我剛剛做了什麼?」「如果有時光機多好!」。這個問題可以很簡單的透過版本控制系統幫你解決。Subversion 就是這樣的系統。

關於 Subversion 的使用相當的容易,只要在 server 端把 Subversion service 建好,並且建立好專案的檔案庫之後,只需要知道 svn checkout、svn add、svn update、svn commit 這四個指令幾乎就很夠用了。關於 Subversion 的使用在此不多提,可以參照 in2 寫的 Subversion Quick Start,看完之後應該就可以開始使用 Subversion 了。

這篇要講的,主要是 Subversion server 架設的部分。這邊以 ubuntu linux 為例,原因?因為室友 GeeLauChen 他用的就是 ubuntu,我的 Subversion service 又剛好架在他的 server 上 XD

既然用的是 ubuntu,那麼記得 apt-get 是你的好朋友!要安裝 Subversion 十分簡單,假設你已經裝好 Apache 只要下:
apt-get install subversion libapache2-svn
就可以把 Subversion 還有跟 Apache 整合的 module 安裝好。

接下來就是設定的部分。ubuntuSubversionApache 整合的設定檔放在
/etc/apache2/mods-available/dav_svn.conf
以下的範例是一個 dav_svn.conf 的例子。
<Location /svn>
  DAV svn
  SVNPath /var/www/svn
  AuthType Basic
  AuthName "Subversion Repository"
  AuthUserFile /etc/apache2/dav_svn.passwd
  <LimitExcept GET PROPFIND OPTIONS REPORT>
    Require valid-user
  </LimitExcept>
</Location>
這邊跟 SVN 有關的有幾行:
<Location /svn>
代表著你透過 Apache 存取 Subversion 檔案庫時的位置,在此我們用的是 /svn,代表位置是 http://server/svn/。
SVNPath /var/www/svn
表示說 Subversion 檔案庫實際存放的位置。
AuthUserFile /etc/apache2/dav_svn.passwd
則是代表驗證檔案的位置,然後接下來的
  <LimitExcept GET PROPFIND OPTIONS REPORT>
    Require valid-user
  </LimitExcept>
則是代表我們利用 Apache 的 LimitExcept 來做存取的控制,這部分請參照 Apache 的說明, 接著我們要建立給 Apache 做認證的檔案。用以下指令:
htpasswd2 -c /etc/apache2/dav_svn.passwd
htpasswd2 這隻程式會讓你輸入密碼。最後是建立起你的檔案庫,用以下指令:
svnadmin create /var/www/svn
就可以建立起新的 svn 檔案庫了。然後重新啟動 Apache,你就可以透過 http protocol 來做 Subversion 檔案庫的存取了。

如果我們不想每次新增加專案的時候都要重新去更改 dav_svn.conf 檔,那麼我們可以把 SVNPath 改成 SVNParentPath,那麼在 SVNParentPath 的所有目錄都會被視為是 Subversion 檔案庫,如此不但不用去更改 dav_svn.conf 檔,Apache 也可以不用 restart,不過隨之而來的壞處就是所有的專案只能夠用一份 .passwd 去做管理。因此需要自己根據不同的需要來做斟酌。如果想要寫出類似 OpenSVN 的 Web 介面,基本上就是去改 config 檔,然後建立檔案庫以及使用者帳號、密碼,接著重開 Apache,室友 Tim 就實做了一套 CloseSVN 給我們自己人用 XD 看看他要不要分享一下心得吧。

Subversion 的架設還有使用基本上大概就是這樣,如果有其他的問題,可以參照 plasma 翻譯的 svnbook,有更詳細的說明。

快快樂樂學 QT - 第一章 Getting Started (2)

Making Connections

在下一個例子當中,將會告訴我們如何對使用者的動作做出回應。這個程式包含了一個按鈕,當使用者點了這個按鈕之後,程式就會離開。這個程式跟 Hello 這隻相當類似,主要差別在於我們用 QPushButton 來代替 QLabel以下是範例:
1  #include <qapplication.h>
2  #include <qpushbutton.h>

3  int main( int argc, char *argv[] )
4  {
5      QApplication app(argc, argv) ;
6      QPushButton *button = new QPushButton("Quit", 0) ;
7      QObject::connect(button, SIGNAL( clicked() ),
8                               &app, SLOT( quit() )) ;
9      app.setMainWidget(button) ;
10     button->show() ;
11     return app.exec() ;
12 }

QT 的 widget 透過 signals 表示使用者的動作或者是狀態的改變。舉例來說,QPushButton會在使用者按下按鈕的時候,發出一個 clicked() signal。Signal 可以跟 function 作連結(接下來這個 function 我們會稱作 slot),也就是說,當一個 signal 被發出的時候,slot 就會自動的被執行。

在我們的例子當中,我們把按鈕的 clicked() signal 跟 QApplication 物件的 quit() slot 做了連結,SIGNAL() 以及 SLOT() 這兩個 macros 是 Qt 語法的一部分,在下一章當中會有更詳細的解釋。

接著我們就來 build 並且執行這個程式,當程式執行之後,如果你按下了 Quit,或是按下空白鍵(代表按下 Quit 按鈕),你會發現程式會結束執行。

下一個例子則是展示了如何利用 signals 以及 slots 讓兩個 widget 同步,這個程式詢問使用者的年紀,使用者可以透過一個 spin box 或是 slider 來作輸入。 程式包含了三個 widgets:QSpinBoxQSliderQHBox (horizontal layout box)。QHBox 是程式的 main widget,QSpinBox 以及 QSlider 被放在 QHBox 裡面,它們兩個是 QHBoxchildren

1  #include <qapplication.h>
2  #include <qhbox.h>
3  #include <qslider.h>
4  #include <qspinbox.h>

5  int main( int argc, char *argv[] )
6  {
7      QApplication app(argc,argv) ;
8      QHBox *hbox = new QHBox(0) ;
9      hbox->setCaption("Enter Your Age") ;
10     hbox->setMargin(6) ;
11     hbox->setSpacing(6) ;

12     QSpinBox *spinBox = new QSpinBox(hbox) ;
13     QSlider *slider = new QSlider(Qt::Horizontal, hbox) ;
14     spinBox->setRange(0,130) ;
15     slider->setRange(0,130) ;

16     QObject::connect(spinBox, SIGNAL(valueChanged(int)),
17                              slider, SLOT(setValue(int))) ;
18     QObject::connect(slider, SIGNAL(valueChanged(int)),
19                              spinBox, SLOT(setValue(int))) ;
20     spinBox->setValue(35) ;
21     app.setMainWidget(hbox);
22     hbox->show() ;
23     return app.exec() ;
24  }


第 8 行到第 11 行我們對 QHBox 做了一些設定,我們在 QHBox 的外圍以及跟 child widget 之間留了一些空間 (6 pixels)。12 和 13 行我們產生了行我們產生了 QSpinBox 以及 QSlider 物件,並且把他們兩個的 parent 都設定為 QHBox

儘管我們沒有明確設定這兩個 widget 的位置以及大小,我們仍然會發現 QSpinBox 還有 QSliderQHBox 當中躺的好好的,這是因為 QHBox 會自動的給他的 child 合理的位置還有大小。Qt 提供了許多像是 QHBox 之類的 classes 讓我們不用刻意去指定 widget 的位置以及大小。

14 以及 15 行設定了 spin box 以及 slider 的合法範圍,16 到 19 行的兩個 connect 則是讓 spin box 以及 slider 作同步的動作,使他們兩個都會有相同的值。當任何一個 widget 的值改變,就會丟出 valueChanged(int) 的 signal,連接到另外一個 widget 的 setValue(int) slot,並且跟著改變值。

第 20 行把 spin box 的值設定為 35,當跑到這一行時,QSpinBox 發出了 valueChanged(int) 的 signal,並且還有一個值為 35 的 int argument。這個 arguemnt 會被傳到 QSlidersetValue(int) slot,把 slider 的值設成 35。接著 slider 又會因為 slider 的值改變了而送出一個 valueChanged(int) 的 signal,不過在這個時候,因為 spin box 的值已經是 35 了,所以不會有 setValue(int) 的發生。這樣可以避免無窮迴圈的狀況發生。

總結一下,Qt 建造使用者介面的方法相當簡單易懂而且有彈性,並且透過 layout,我們可以不用擔心 widget 的大小還有位置問題。UI 的行為則是透過 widget 之間的 signals 還有 slots 機制來作管理。

快快樂樂學 QT - 第一章 Getting Started (1)

這一章是我們簡介 QT 的開始,我們將會由一個最經典的 "Hello QT" 的例子,先讓大家看看 QT 的程式會長什麼樣子。在此,也會介紹兩個 QT 的概念:"siganls and slots" 以及 layouts。

Hello Qt

那麼,先讓我們來看看 "Hello QT" 這個程式:
1  #include <qapplication.h>
2  #include <qlabel.h>

3  int main( int argc, char *argv[] )
4  {
5      QApplication app(argc, argv) ;
6      QLabel *label = new QLabel("Hello Qt!", 0) ;
7      app.setMainWidget(label) ;
8      label->show() ;
9      return app.exec() ;
10 }

第一、二行 include 了 QApplication 還有 QLabel 這兩個類別的 definitions,第五行建構了一個 QApplication 的物件來管理程式的資源,QApplication 的 constructor 需要 argc 以及 argv 當作參數。這是因為 QT 也支援了一些 command-line arguments。

第六行建構了顯示 "Hello Qt!" 的 QLabel widget,在 Qt 當中,一個 widget 指的就是一個 UI 上面的視覺元素。按鈕、選單、捲軸等等,都是 widget 的例子。Widget 當中也可以包含其他的 widgets,舉例來說,一個程式的視窗就是一個 widget,通常會包含 QMenuBarQToolBarQStatus,還有一些其他的 widget。後面傳給 QLabel constructor 的參數 0 (null pointer) 代表這個 widget 所在的視窗就是他自己,而不是一個在其他視窗當中的 widget。

第七行把 label 設定成程式的主要 widget,當使用者把主要 widget 關掉之後,程式就會結束。如果沒有設定主要 widget,程式會在關掉視窗之後依舊在背景一直執行。第八行讓 label 可以被看到,在 widgets 剛被建構的時候都是被設定為隱藏的,這樣我們可以在 widgets 被看到之前先對它們作設定。第九行把程式控制權傳給 Qt,在這個時候,程式進入到一種 stand-by 模式,等待使用者滑鼠、鍵盤等等的動作。

現在讓我們來測試一下程式吧!首先,我們需要先安裝 Qt3。我們假設你已經把 Qt3 裝好了,並且已經把 Qt 的 bin 目錄設定在你的 PATH 環境變數當中。

現在我們可以把這個程式取名叫做 hello.cpp,並且把他放在一個叫做 hello 的目錄當中。利用命令列,先切換你的目錄到 hello,打入
qmake -project
來創造一個跟平台無關的專案檔案 (hello.pro),接著再打入
qmake hello.pro
來從專案檔案當中創造一個平台相關的 makefile,執行 make 來 build 這個程式,接著執行 hello,就會看到程式的結果跑出來。

接著讓我們再來試試看一些東西,我們可以在 label 上面動一些手腳,透過插入一些簡單的 HTML-style 標籤格式,只要把這行
QLabel *label = new QLabel("Hello Qt!", 0) ;
改成
QLabel *label = new QLabel("<h2><i>Hello</i> ""<font color=red>Qt!</font></h2>", 0) ;
然後再 rebuilding 這個程式就可以看到新的結果。

快快樂樂學 QT - 前言

我知道這個標題很蠢,不過一時之間我想不到什麼其他好標題 XD

這串文章主要是記錄一些我學習 QT 的心得,主要是依照 C++ GUI Programming with Qt3 的內容為主,然後會附上一些自己的心得。大致的把學習過程作個記錄,以後也可以給有需要的人稍微作個參考。在這裡,我還是會以 QT3 為主軸。原因很簡單,儘管 QT4 已經推出一段時間了,但是因為目前手上只有這本書,因此為了不必要的麻煩,就先以 QT3 為基準。等到整本書看的差不多之後,再去就兩個版本之間不同之處來作比較。
 

Popular Posts