Qtopiaアプリケーションの開発 その2 ソースの流れを追う

 さて、ようやくQtopiaアプリケーションの開発に取り掛かったのは良いんですが、そもそもC++からしてよく分かってなかったりします(爆)。無印のCは一応少しは分かるんですが(苦笑)。

 てな訳で、C++もまとめて一緒にお勉強状態です。この先、色々とQtopia以前の話も出てくると思います(^^;)。


 まずは、お勉強の第一歩として、これまでの動作テストで使ったサンプルソース(HelloQT)の流れを追ってみることにします。

# main.cpp

 1: #include 
 2: #include 
 3:
 4; int main (int argc, char *argv[])
 5: {
 6:	QPEApplication hello( argc , argv );
 7:	QLabel *label = new QLabel ("Hello World!",0);
 8:	hello.setMainWidget(label);
 9:	label->show();
10:	return hello.exec();
11: }


・1〜5行目
 このへんは、従来のCとさほど変わりはありません。

 使用する関数に応じて、ヘッダをインクルード。で、実行部はmain関数で囲います。

 注意点は、インクルードするヘッダファイルの差異についてです。

 通常、Qtアプリケーションでは、まず最初にqapplication.hをインクルードします。実際、手元のQtの参考書に載ってるソースでは大概そちらが記述されています。

 しかし、上のソースではqapplication.hの代わりにqpeapplication.hがインクルードされています。

 この違いは、そもそもZaurus上で動いてるシステムに起因します。

 ZaurusQtopia環境は、Qt/Embeddedと言うQtのサブセットで動作しています。QtとQt/Embeddedは、基本的な部分での互換性は確保されており、通常のQtアプリケーションを動作させることも可能ではあります。
 ただ、厳密にZaurus(Qtopia)用のアプリケーションを組む場合は、当然ながらQt/Embedded用のアプリケーションを作成する必要がある訳です。

 で、ぶっちゃけた話、Qt/Embedded用にアプリケーションを組むにはどうすれば良いか?と言うと、qapplication.hの代わりにqpeapplication.hをインクルードする、だけだったりします(^^;)。

 qapplication.hとqpeapplication.hでは、単純なウィンドウの見た目とかだけで無く、勿論、使える関数やライブラリにも色々と差異があります。
 ただ、ウィンドウを構成するボタンやラベル等と言った各パーツに関しては、共通のものを利用するので、続いてインクルードされてるqlabel.hqpelabel.hなんかになったりはしません。


6行目

QPEApplication hello( argc , argv );

 早速、怪しくなってきました(^^;)。

 えーと、とりあえず、これはクラスに関わる記述です。
 具体的にはQPEApplicationクラスのオブジェクト「hello」を新規に定義しています。
 クラスは、内部に値を保持する変数だけでなく、機能を持つ関数も含めることが出来るため、まとめてオブジェクトと呼称するそうです。

 ただ、逆に言えば、この記述は機能的な差異はともかくとして、ソースの本質的には

int a=0;

と大差は無いってことですか。

 変数を使用する際は型を指定し、ソース中の変数名を設定します。
 同様に、クラスを使用する場合は、使用するクラスを指定し、ソース中のクラス名を設定する、と。そう考えてくと、まぁ、分かりやすいかな?。


7行目

QLabel *label = new QLabel ("Hello World!",0);

 思いっきり分かりません(爆)。

 とは言え、前項のことも踏まえると、型(クラス)を指定して新たなポインタ(*label)を設定し、後に続く値を代入してるらしいことまでは大体分かります。

 要は、その値の指定方法の表記ですな(汗)。

 で、調べてみると、ここで使われてる「new」演算子は、動的にヒープ領域のメモリを確保するもんらしく、いわゆる無印Cでのmalloc関数と同等のものみたいです。・・・まぁ、そのヒープ領域ってのがよく分かんないんですが(^^;)。

 えーと、だからこの場合、後ろのQlabel();の定義内容をメモリ上に確保し、そのアドレスをポインタ*labelに収めてる訳ですか。
 ・・・なんか、直接文字列をポインタで渡すんでも良いよーな気もしますが、このへんはQtの仕様みたい。

 しかし、それはともかく、この「new」演算子で確保したメモリ領域は「malloc」に対する「free」と同じく、「delete」演算子で解放しないといけないとC++の教科書には書いてあります。
 でも、このソース見る限りでは、main()の最後でhello.exec()の戻り値だけ返して処理終わる格好になってますな。
 ・・・Qtって、アプリケーション終了時にちゃんとメモリ解放してくれてるんでしょーか?(^^;)。そのへんがQtアプリでやたらメモリリーク発生する原因だったりせんでしょうな(汗)。


8行目

hello.setMainWidget(label);

 6行目で定義したオブジェクト「hello」のメンバ関数setMainWidgetに*labelの中身を引き渡してます。

 Widgetウィジェットってのは、ウィンドウ&オブジェクト&ガジェット辺りの用語をひとまとめにした造語で、要はGUIにおけるウインドウや、ボタン、テキストボックスなどの各パーツの総称です。
 QtopiaアプリケーションはGUIである以上、当然、一番基本の土台となる親ウィンドウが、アプリケーションにつき必ず一つは存在します。それがメインウィジェットになる訳ですな。

 今回引き渡してるのはQlabel=ラベルな訳ですが、恐らく他のウィジェット(部品)もこんな感じで各ウィジェットを、さらにその親となるウィジェットに引き渡していき、最終的に全体のウィンドウが形成されていくんでしょう。


9行目

label->show();

 またまた、勉強が必要な表記が(苦笑)。

 「->」はアロー演算子と呼ばれるもので、クラスをポインタ表現で表す際の表記方法の一つらしいです。
 そもそも、クラスは複数の変数・関数の集合体、いわば超デッカい配列みたいなもんなんで、ポインタを使って取り扱う場面が出てくることは、まぁ分かります。

 で、その上でクラスのメンバを指定する場合、単純に

 *class.member

てな表記でいけそうな気がするんですが、これはNGになります。と、言うのもこの表記だと、ポインタ演算子「*」が「class.member」全体にかかってしまうからです。
 あくまでも、ここではポインタ「*class」で示されるクラス中のメンバ「member」を指定したい訳なんで、

(*class).member

と、明確に括弧で括ってやって、はじめて意図した結果が得られます。

 で、いちいち括弧で括るのは面倒(爆)だろうってんで、生まれたのがこのアロー演算子らしいです。上記をアロー演算子を用いて表記すると、

class->member

となります。ポインタ「class」から導かれるメンバだから、右向きの矢印ってことみたい。・・・何か、個人的には括弧で括る方が分かりやすい気が(苦笑)。

 ま、とりあえず、アロー演算子について分かったところで、改めてソースに戻り、上記に従って翻訳すると、要はここの表記は

(*label).show();

ってことになります。
 なんだ、結局*labelで示されたQlabelクラスのメンバ関数show()を実行してるだけですか(苦笑)。


10行目

return hello.exec();

 前項で書き忘れましたが「.」はクラス内のメンバ(変数・関数)を指定する際に用います。
 helloはQPEApplicationクラスのオブジェクトなんで、つまり、ここのexec()はQPEApplicationクラス内で定義されているメンバ関数です。

 で、その戻り値をそのままmain関数の戻り値として返す形で、main()が終了してます。
 ってことは、逆に言うとここまで来て、ようやくアプリケーションが動作し始めるってことですね。



 ここまでソースを追ってみた限り、基本的にQtopiaアプリケーションの流れは、

  1. 各パーツ(ウィジェット)のパラメータを設定
  2. 設定の終わった各パーツ(ウィジェット)を親(ウィンドウ)にセット
  3. 全ての設定と、パーツ配置が終わったところで、おもむろにメインウィジェットを実行

って流れになるようですね。

 このへん、前にちょっと触った qshdlgと感覚的には同じなんで、割とすっと理解することが出来ました。してみると、qshdlgは、Qtopia触るための入り口として、非常に良い教材でありますな(^^)。