トップページ>>>「ぷろぐらみんぐ」目次

Qtで遊んでみました第一回。

初版作成:2002/12/24

注意

2008/11月現在、実に6年前のドキュメントになっています。「昔はこうしていた」という参考としてご利用下さい。

目次

  1. 前書き
  2. 本題
  3. 後書き或いは感想

前書き

 杉田研治著の「KDE プログラミングパーフェクトガイド」を一通り読み終えました。
 読もう読もうと思っている内に、いつの間にやらQt, KDEともに3.Xが出始めてしまいました。
 まあ良いのです。出遅れるのはいつものことだし(自慢できないか)。
 んでですね。後書きでいろいろ管巻こうとは思っていますがとにかくQtDesignerとtmake, progenでもって ちこっと何か作ってみようかな、と思ったわけですよ。
 そう言うわけで、できたのは「ボタンが二つあって、PushButton1をクリックするとアプリ終了。」という 、「なぜ二つあるのだから両方オッケーにしないのか」とかゆー手抜き具合に関してのクレームは無視しますみたいな 感じのお試しジャンクです。
 とりあえず、手順をざっと追っただけという自分自身のリファレンス用(又かよ)に作ったので、わかりづらさは 勘弁してください。いずれ、Qtのインストールから追ったきちんとしたページを作ると思うので。
 さ、急ぎましょう。ざっと追うだけです。

目次に戻る

本題

  1. Qt環境、知識の確認。
  2. とにかく作る。

Qt環境、知識の確認。
「本題」に戻る
 使用ディストリビューションはTLXW8でフルインストールです。
 従ってQtはdevelパッケージも一緒に入ります。
qt-2.3.1-21
qt-devel-2.3.1-21
 Qtにコアに関連してくるパッケージはこれぐらいですか。
[fenjin@seisyuu fenjin]$ rpm -ql qt
/etc/profile.d/qt.csh
/etc/profile.d/qt.sh
/usr/lib/qt
/usr/lib/qt/lib
/usr/lib/qt/lib/libqt-mt.so.2
...ライブラリ色々。
/usr/share/doc/packages/qt-2.3.1
/usr/share/doc/packages/qt-2.3.1/ANNOUNCE
...ドキュメント色々。

[fenjin@seisyuu fenjin]$ rpm -ql qt-devel
/usr/bin/designer
/usr/bin/findtr
/usr/bin/makeqpf
/usr/bin/mergetr
/usr/bin/moc
/usr/bin/msg2qm
/usr/bin/qconfig
/usr/bin/qt20fix
/usr/bin/qtrename140
/usr/bin/uic
/usr/include/qt
/usr/lib/qt/bin
/usr/lib/qt/bin/designer
/usr/lib/qt/bin/findtr
/usr/lib/qt/bin/makeqpf
/usr/lib/qt/bin/mergetr
/usr/lib/qt/bin/moc
/usr/lib/qt/bin/msg2qm
/usr/lib/qt/bin/qconfig
/usr/lib/qt/bin/qt20fix
/usr/lib/qt/bin/qtrename140
/usr/lib/qt/bin/uic
/usr/lib/qt/doc
/usr/lib/qt/doc/html
...あといろいろなドキュメントとか。一応manページもインストールされている。
 といった感じです。結局、/usr/lib/qt/ディレクトリ以下にQt関連のすべてが納められている、 と考えて良いです。この中のサンプルとか、チュートリアルとかも、既にある実行ファイル動かすだけでも面白いですよ。

 ただし、このdevelパッケージにはQtプログラミングを楽にしてくれる「progen」と「tmake」が含まれていない、という致命 的なミスがあります。
 これに関してはどーしよーもないので、Trolltechのホームページ にダウンロードパスが載っていますので、てきとーに探しててきとーにFTPで落としててきとーに/usr/local/binあたりにでも つっこんどいてください。動作確認までは今回はサポートしません。いずれきっちりやりたいとは思いますが・・・今回の参考本 みりゃ良いわけだし。とりあえず、動いた、としときましょう!!
 んじゃ、とりあえず作りましょう・・・のまえに。「./configure, make, make install位しかやったこと無いんだけど。」と 言う人のために簡単な用語集でも拵えておきましょう。あ、C, C++はある程度知ってるを前提にしてますよ。

・progenってなに?:「make」コマンドをぶったたくにはコンパイル手順を記述した、俗に言う「メイクファイル」が必要です。 progen, tmakeは何と、「ソースコードを見ただけでメイクファイルをとりあえず作ってくれちゃう便利なソフト」なの です。もっともQt開発用に特化してるみたいではありますが。
・tmakeってなに?:上記の質問の続きですね。progenで生成されるのは、コンパイルに必要なソースのリスト、みたいなもんです。 ここから実際のMakefileを生成してくれるのがtmakeです。
・Qtプログラミングって、Windowsプログラミングとどう違うの?:もしあなたがVC++やC++Builder, Delphi等を触っているなら 非常に話が早いです。その世界で言うところの「イベント」「イベントハンドラ」は、Qtでは(非常に大胆な例えであるが)「 シグナル」「スロット」として実現します。Qtのボタンや何かにはあらかじめ典型的な「シグナル」(実際には関数)が実装済み です。あとは、「スロット」をこちら側で定義してあげます。ここまではWindowsと一緒です。
 違うのはその先です。Qtでは、connect関数とかユーのをつかって「シグナル」と「スロット」を自由につなげることができます。 やろうと思えば「シグナル」と「シグナル」をつなげることもできます。
 ぶっちゃけた話、「シグナル(SIGNAL)」も「スロット(SLOT)」も関数で、イメージとしては「関数のポインタをつなげる」みたい な。実際問題、シグナルとして定義する関数は実装しなくて良いんです。ほっといて良いんです。
 とにかく、「イベント」と「イベントハンドラ」を、WindowsのMessageシステムがないLinux, UNIX上でどうにか実装しようと 試みた結果が「シグナル」と「スロット」になったみたいな。
 というわけで、両方ともその実体は関数です。どうやって関連づけしてるのか、その内側まではまだわかりません。

 以上。え?短い?・・・ま、まあ。今回は雰囲気だけ感じ取ってもらえれば・・・さ!次いこっか!

参考資料
・「KDE プログラミングパーフェクトガイド」杉田研治 技術評論社

とにかく作る。
「本題」に戻る
 とりあえず、作業用のディレクトリを作ります。今回は「Test Class 1」を省略して「tc1」ディレクトリを適当な場所に作り ました。
 んで、KDEのメニューから「開発」カテゴリの「Qt Designer」を選びます。初回起動時には何か聞かれてきたような気もします がもう忘れました。とにかく適当に返事して先に進みましょう。
 んで、「新規作成」します。

 新規作成するとこんなDLGが表示されるので、とりあえずWidgetを選択してOKします。

 すると、C++Builderではお馴染みの「Form1」と「Property Editor」が表示されて起動します。

 さて、ここでBCB(C++Builderのこと)になじんでいる人ならボタンを二つは位置するくらいは即行でしょう。ツールバーにさっそく Qtウィジェットが色々並んでますね。
 あ、ウィジェットってユーのはすごい乱暴な例えですがMFCとかVCLにあたります。

 はい。とりあえずPushButton二つてきとーに配置します。

 フォームがでかすぎるので、Form1の右下をドラッグして縮めます。

 マウスでボタン二つを選択状態にします。

 さて、ここでQtオリジナルのAlignmentシステムの登場です。Qtでは部品の配置に関して「升目上に簡易的に配置」機能を提供 してくれています。まあ・・・直接座標指定でも良いんですが、ボタン一つで結構見栄え良くなるので。
 ボタン二つが選択状態で、「Layout」メニューから「LayOut Vertically」を選択します。すると・・・

 こんな感じにさくっと垂直に並んでくれました。

 んで、いよいよシグナルとスロットの準備をします。今回はまず、PushButtonのclecked()シグナルを関知するためにForm1側に slotForm1Exit()スロットを設けます。Form1上を普通にクリックした後、右クリック。

 メニューから「Slots」を選択します。

 こんな感じのDLGが表示されるんで、こんな感じにslotForm1Exit()を登録します。

 んで、「Tool」から「Connect Signal/Slots」というそのものズバリを選択。PushButton1で左ボタンを押し、そのままForm1まで マウスポインタを持ってきます。

 ちょうどこんな感じになるかも。こんな風に枠線が両方に表示されれば、マウスは放し?謄?奪院次?

 マウスを放すと、こんなDLGが表示されます。直観的に「clicked()」を選択状態にした後、「slot Form1Exit()」をクリックすれば自動的に下の「connections」に追加されます。

 この段階でOKすれば、めでたくPushButton1とslotForm1Exitがつながりました。これでもう、QtDesigner上での作業はおしまい です。え?コンパイルは?・・・そこまではQtDesignerはしません。いえ・・・KDevelopはしてくれるんですけど・・・。  ま、まあ、何で私がKDevelopではなくてQtDesignerを試したかの話にもつながりますので、今は不問にして置いてください。

 後は「File」「Save As」で、「test.ui」という名前で保存しておきます。Windowsとクリソツ な見た目ですが、このどうみてもSaveDialogだろと言いたくなるようなDLGは/usr/lib/qt/のサンプルに入っています。
 「Preview」の「Preview Form」で文字通り、実行時の画面を確認できます。

 ちなみに今回は最終的にこんな感じ。

 んで。今は何も考えずにtc1/に移動して、以下のコマンドをぶっ叩いてください。
$ uic test.ui -o test.h
$ uic test.ui -i test.h -o test.cpp
$ uic -subdecl tc1 test.h test.ui -o tc1.h
$ uic -subimpl tc1 tc1.h test.ui -o tc1.cpp
 前半でForm1クラスの基本定義ファイル、実装ファイルを自動生成してくれます。BCBと一緒。後半はちょっと変わってて、 前半で作ったクラスを派生させることにより、いわゆる「ラッパークラス」みたいな感じの定義ファイルと実装ファイルを生成 してくれてます。うまく使いこなせばデザインは基本定義ファイルに。実装部はラッパークラス側にまとめることにより、デザイン と実装を分離できる・・・らしいです。
 ここでちょっとtc1.cppに細工します。slotForm1Exit()を、さらに自分自身で(これから)定義するExit()シグナルを発生させる トリガーっぽくしましょう。

PushButtonのclicked→Form1のslotForm1Exit()→Form1のExit()シグナル→アプリケーションの終了用スロット

 ・・・と、つなげるためです。え?何でPushButtonのclickedを直接アプリにつなげないか?・・・あとでやってみます。
 ま、まあとにかく。以下のようにtc1.h, tc1.cppを修正します。
tc1.h:
(修正前)
public:
    tc1( QWidget* parent = 0, const char* name = 0, WFlags fl = 0 );
    ~tc1();

protected slots:
    void slotForm1Exit();
(修正後)
public:
    tc1( QWidget* parent = 0, const char* name = 0, WFlags fl = 0 );
    ~tc1();
//ここで、ユーザー定義のシグナル関数を作っときます。
signals:
        void Exit();

protected slots:
    void slotForm1Exit();

tc1.cpp
(修正前)
void tc1::slotForm1Exit()
{
    //qWarning( "tc1::slotForm1Exit() not yet implemented!" );
}
(修正後)
void tc1::slotForm1Exit()
{
    //qWarning( "tc1::slotForm1Exit() not yet implemented!" );
        emit Exit(); //ここで自分自身のシグナルExit()を発動してます。
}
 んで、後は何も考えずに以下のmain.cppを作ります。
#include <qapp.h>
#include "tc1.h"

int main(int argc, char **argv)
{
        //create QApplication Object
        QApplication app(argc, argv);

        tc1 hogehoge(0, "hunyann");
        app.setMainWidget(&hogehoge);
        hogehoge.show();

	//このconnectで最後のシグナル→スロットをつなげる。
        QObject::connect(&hogehoge,SIGNAL(Exit()), &app, SLOT(quit()));

        return app.exec();
}

 ・・・さて、後はもう一息です。これでソースコードの準備は完了しました。では、早速progenとtmakeの威力を見てみましょう。
 とりあえず
$ progen -n tc1 -o tc1.pro
$ tmake tc1.pro -o Makefile
 これだけでMakefileができちゃいました。ね?簡単でしょ?んじゃ早速makeしてみてください。

 ・・・失敗した、と思われます。これはですね、progenはカレントディレクトリ内の「すべての」ソースコードをコンパイル あーんどリンク対象としてしまうからなんです。そのため、test1.oとtc1.oでシンボル名が衝突してしまったんじゃないか、と まあ、見た感じそんな気がするエラーが吐き出されたと思います。
 んじゃあ後は簡単。progenの吐き出すtc1.proから、test.cppに関する記述を省けばいいわけです。
 最終的なtc1.proです。
TEMPLATE        = app
CONFIG          = qt warn_on release
HEADERS         = tc1.h
SOURCES         = main.cpp \
                  tc1.cpp
INTERFACES      = test.ui
TARGET          = tc1
 これでもう一度tmakeしたMakefileを使えば、今度こそうまくいくはずです。

 いかがでしょうか。とりあえず./configureの吐き出すメッセージに恐怖する必要はなくなったと思います。
 結局、Qtはmakeに対して非常に素直なビルド環境を提供してくれているわけです。Autoconfは使う必要はありません。
 初心者にとってはだいぶ透明度が高いという意味で非常に安心できる開発環境だと思います。

目次に戻る

後書き或いは感想

 えー・・・んじゃ、管でも巻かせていただきます。
 KDEの勉強をしていて思ったのですが、「巨大すぎる・・・。」
 WindowsみたいにGUIがレジストリと共にシステムと密接に関わっている「ように」つくっているため、KDEデスクトップ用の プログラムを作るとなるととにかく、でかい。
 しかもQtと組み合わせて動くようにしているため、「Makefileで何してるのか全くわからない。」
 ・・・あんまり、気持ちよい環境ではなかったんです。しかもソースを全部CVSで管理する必要があったし。
 正直、UNIXプログラミング初心者向きでは無いと思います。
 いえ。まあ・・・これを通してCVSの使い方とか覚えられたので一概にNGとも言えないんですが。

 ただ、やっぱり自分の好みとは違う方向へすっ飛んでいっているみたい。
 できればQtはデスクトップ環境の整備なんかはKDEに押しつけて、「シンプルだけど拡張性に富んだ柔軟な」ライブラリで居続けて 欲しい。基本に徹しつつ、それでいてカスタマイズによっては非常に柔軟な面も見せる・・・って、それCetaの目指していたところ なんだよね。

 まだ・・・大丈夫かもしれないけど。Linuxって、RPMとかライブラリとかが絡みすぎていつの間にか下手なWindowsアプリケーシ ョンよりもブラックボックス化して、巨大化して、複雑化してない?
 結局、ソースコードが公開されていようがいまいが一般ユーザーには何の関係もない。
 そう言いきってしまえれば簡単なんだけどね。

 結局、中間層が欠如し始めてるのかもしれません。
 まあ自分で埋めていくものなんでしょう。
 慣れなんでしょう。

 とにかく、大きな開発セットが必要なKDEやKDevelopは自分の好みと一致しませんでした。
 逆に、単に*.uiを作るだけに徹してくれているQtDesignerに惹かれました。
 KDEの開発セットを理解し切れて、QtDesingerでも捌ききれなくなったらKDevelopに移行したいと思います。
 それまではZaurus Linux関連の話もあることですししばらくはQtとつきあっていきたいと思います。
目次に戻る

トップページ>>>「ぷろぐらみんぐ」目次