VC++5.0入門20
チュートリアル読書会2 97/2/8

こんにちは。今回はチュートリアル第4章(ドキュメントの項)の前半、ドキュメントの管理の前までを読む(あるいは読んで手を動かす)ことにします。つらいところですが、みなさん、がんばりましょう。
第4章と第5章(ビューの項)は、初心者にはもっとも重要なところとなります。この2つの章に書いてあることはなるべく多く理解した方が良いでしょう。ただ、最初からすべてを理解しようとはせず、少しづつ実行して、考えて、、、とやっていった方が良いと思います。これは私自身の経験です。とにかく、すべてを最初からと、意気込むより、わかるところから、少しづつ、、の方が、最後に到達できる点は、はるかに上のように思います。

では、一応、先に読んだ者として、いくつかアドバイスをします。ただ、前にも言いましたが、一応、個人的なアドバイスであり、人によっては全然違う読み方をするかもしれません。あとは、みなさんの責任で判断してくださいね。^^;)

まず、いくつか注意です。
1.を動かすべきだと思います。
2.ただし、第4章を完成させてもまだ、その成果は見れません。第5章の完成まで待ちましょう。
3.「詳しくは○○を読んで下さい、、、」は最初は読まなくて良いと思います。
  この「詳しくは、、」は主に別売りのマニュアルか(おそらく同じ内容の)ヘルプ(インフォビュー)を指していますが、私個人は、この辺を読み出すと頭が破裂しそうになりました。(今でも、、、^^)まあ、読める人は読んで、そうでない人は後にまわしましょう。
4.実際に行うことは、AppWizardが生成してくれた初期ファイルの書き換えです。
  ClsaaWizardやWizardBarの説明が、増えてきます。これらは、手でファイルを書き換えても同じであることを、楽にやってくれるだけです。何か神秘的なことをやっているのではと、ビビる(怖がるという意味です)必要はありません。
5.ポイントをつかむという意味で表や図に注目すると良いと思います。
  解説を読んでいると、何がなんだかわからなくなることがよくあります。(私の場合。)それより、まず、表や図を見て、考え、それでなんとなくわかったら、必要そうな解説を読む、、、という態度で私はチュートリアルを読みました。(もちろん、そうでない人もいるでしょう。)

まあ、いつもの注意ですね。
あと、ひとつ、自分で「読書会」をはじめてみて、思ったのですが、すべてを説明することはできないということです。なんか、例のごとしの言い訳っぽいですね。実際、何もかも書けるほど、時間が無いということもありますが、そんなのが書けても、それは他人には読めないものでしょう。それに、やっぱり、自分で考えて悩むという経験がどうしても必要だと思います。プログラムの勉強には、どうしてもそういうところがあります。


この章を読むにあたって、基礎としてテンプレートクラスの知識がちょっと必要です。これはC++入門では説明しませんでした。ごめんなさい。ただ、私の経験では、これはこういうものであるという説明を聞くより、使っていて覚えるという方が早いような気がします。一応、どんなものかだけ説明しましょう。
テンプレートクラスというものは、何かパラメータを持ったクラスのことです。例えば、VC入門12でも説明しましたが、MFCにはCArrayというテンプレートクラスがあるのですが、例えば、
    CArray<int, int> one;
と書くと、oneがMFCの整数の配列になるものです。どうして整数になったかというと、それは、<int, int>と書いたからです。このintがパラメータなのです。なんでintを2回繰り返すのかというと、いろいろ事情があって、MFCの設計者がそう決めたのです。(今、詳しく知りたい人はヘルプを読んでください。ごめんなさい。)
それで、たとえば、Nekoというクラスが定義されていたとすると、
    CArray<Neko, Neko> one;
でNekoの配列になります。
こういうテンプレートクラスは誰かが設計して、使うものです。(もちろん、みなさんが設計してもよいですが、それはまた後にしましょう。)パラメータ(つまり、<と>の中身)がどうなっているのか、どう設定するのかは、そのテンプレートクラスの設計者が決めることで、使用者(つまり私たち)は、従うしかありません。MFCのテンプレートクラスはいろいろあって覚えるのは大変そうですが、これもはじめから全部覚えようとしないで、まず、チュートリアルの真似をする、、、というところからはじめましょう。(ちょっと、嫌なところですが、、、。)

さて、能書きはこのくらいにして、チュートリアルを、見てみましょうか。
まず、最初の方に、MFCプログラムの基本的な構造を表す「主要オブジェクト」の説明があります。最終的には、これを理解する必要があるのですが、はじめはちょっと難しいかもしれません。5つの主要オブジェクトのクラスのうち4つまでは、VC入門8で説明しましたが、覚えていますか。あとひとつのドキュメントテンプレートは、後で説明しましょう。
まあ、最初はわからなくて当然だと思います。ただ、ちょっとがまんして図4.1(ヘルプには見当たらない?)と表4.1(アプリケーションの主なオブジェクト)を見ておいてください。その心は「第5章を読み終えた頃にもう一度見直して理解するぞ」です。今、理解する必要はないですし、たぶん、普通は無理だと思います。したがって、解説はななめ読みで良いと思います。(ヘルプには番号が無いので、一応、図や表の題名を書いておきます。しかし、これは製本されたものと微妙に違った名前のようです。あまり、気にしないでください。それから、私はバージョン4.0についてきたチュートリアルを見ているので、もしかすると、バージョン5.0では番号がずれていたりするかもしれません。気が付いたらお知らせください。ぜひお願いします。)

次に、ドキュメント・ビューの話題がありますが、多分、概念的にはここが一番大事です。図4.2(ヘルプに無い?)を見てください。
要するに、MFCプログラムでは、データを扱う「ドキュメント」というクラスのオブジェクトがあり、主要なデータはみなそこに貯える、そのデータを実際にウインドウに表示するには、ビューというクラスのオブジェクトを使うということです。、、、、難しいでしょうか?私の単純化したイメージでは「ドキュメント=データ」「ビュー=データを見る窓」です。

図4.3(ヘルプに無い?)とその辺の解説は、理解できることにこしたことはないですが、とりあえず、第5章が終わってから、考え直して良いと思います。ただ、ななめ読みだけはしておきましょう。

それから、CScribbleDocへのコードの追加がはじまります。これが、実際に手を動かす本番ですね。 まず、注意することは、ここで付け加えるコードは、プログラムのある程度の完成を考えてのもので、その説明は後回しになっているということです。この辺で、わからないと悩む人が多いようですが、わからないのはあなたが正常だからです。超能力者(予知能力者)かプログラミング熟練者しかわからないはずなのです。
しかし、超能力者や熟練者でなくても道はあります。それは、とにかく終わりまで読んで、後で考え直すというものです。実際、多くのツワモノはそうやって読んでいると思います。自信のある人は以下のアドバイスを読まずに、ごりごりやってみてください。(本気です。)ただ、まあ、何をやっているのか方針だけは、知りたいという人は、下を読んで下さい。それも悪くないと思います。

このプログラムは、Scribble(落書き)というプラグラムで、完成後は、画面に線を書きなぐるプログラムです。というとペイントブラシを思い出しますが、ちょっと、雰囲気が違います。(といって、ペイントブラシが実際に内部で何をやっているかは知りません。あくまでも雰囲気の話です。)このプログラムでは、ひとつひとつの線を個別のデータとして扱っているのです。つまり、できあがったものは「絵」ですが、プログラムでは、ひとつの「絵」というよりむしろ「線の集まり」として扱っているのです。こうする理由は、他のプログラムへの応用を考えたチュートリアルだからだと思います。
さて、そうすると、「線」の集まりがデータとなるわけですが、その「線」を表すクラスをCStrokeとしています。Strokeは、ラケットなどの一振を表すストロークですが、たぶん、ここでは筆の一振を表しています。つまり、「一筆(ひとふで)」というやつですね。
チュートリアルの順番は少し違っていますが、とにかく、必要なことは、このクラスを定義することです。これは第4章の途中でやっています。このクラス(のオブジェクト)は、基本的に、点の集まりです(線=点の集まり、、、ああ、中学校の頃やりましたね)から、CArray<CPoint, CPoint>が主なメンバですね。
この「線=一筆」をたくさん集めて保持しておくのがドキュメントです。どうしましょうか?ここでは、ユーザが一筆書くごとに、new演算子を使って、一筆(CStroke)のオブジェクトを作る方針です。(全貌は次の章で説明されます。第4章を読んでいる初心者には読みづらいですね。しかたないんですが。)
newはオブジェクトを生成し、そのオブジェクトへのポインタを戻す(示す)演算子ですから、たくさんの「一筆」を保持するためには、CStrokeへのポインタを保持するコンテナ(入れ物)がほしいですね。そのようなコンテナにMFCではCTypedPtrListというテンプレートクラスが用意されています。このクラスの使い方は、ちょっと難しいと思います。(とても嫌です。)しかし、まあ、最初はチュートリアルにある使い方を覚えましょう。実際、よく考えると、チュートリアルの内容を真似るだけで、けっこういろんなことができます。まあ、それはあとで考えるとして、、、。
CStrokeオブジェクトへポインタの集まりを保持するためには、
    CTypedPtrList<CObList, CStroke*> m_strokeList;
とすればよいのです。こうするとm_strokeListがお望みのコンテナになります。上のCObListってなんだと思うでしょう。これは、このクラスで後述(次回)のシリアライズを使うときには、いつもCObListと書くと、覚えておけば良いと思います。このオブジェクトがドキュメントのメンバになるわけです。ドキュメントがデータを管理するのですから。
この辺のデータの構造は図4.5(「Scribble の m_strokeList データ構造」)を見ると良いでしょう。○がCPointを表し、その集まりの四角がCStrokeのオブジェクトで、●がCStrokeへのポインタを表し、その集まりの四角がm_strokeListを表しているのです。(と、思います。まあ、概念図ですから、絶対そうだとは言い切れませんが。)やはり、こういう図や表から入っていくのが良いと思います。

まあ、重要なアドバイスはこんなところでしょうか。後は、手を動かす前に、表4.3と4.4(ヘルプでは「CScribbleDoc のメンバ関数とメンバ変数のまとめ」)を見ておいても良いかもしれません。これらのメンバを書き加えたり、書き換えたりするわけです。(初期ファイルのままのもあります。)たったこれだけだと思えば、気が楽ではないでしょうか。表をちらちら見てください。
CPenとかペンという言葉がちょっと目に付きますね。Scribbleでは「線」を書いていくのですが、太い線や細い線などいろいろな線が書けるようになります。この線の太さなどは、どうやって変えるのでしょう。実は、おもしろいことに、画面に線を引く時には、CPen(ペンを表すクラス)というクラスのオブジェクトを作って使うのです。このCPenつまりペンが太かったり細かったりで、線の太さが変わるのです。(なんかC++的ですよね。)そのために、CPenオブジェクトがドキュメントのメンバになっているのです。CPenの使い方は、また、後で、考えましょう。とにかくそういうもんだと思っておいてください。
あと、VC入門のこれまでの説明とあわせれば、大体のメンバの意味はわかるのではないでしょうか。ちょっと、わからないのは、AssertValidとDumpですが、今は、とばしておいて良いと思います。どうせ、書き換えませんし、チュートリアルでは使いません。

それでは、CScribbleDocへのコードの追加」をはじめてください。「ドキュメントの管理」の前までの内容について、ちょっとコメントを付けますが、それは、やりながらでも見てください。

1.ClassViewで、右ボタン+[変数の追加]や[関数の追加]で、やっていることは、エディタを使って手でもできることです。(くどいですね。)
2.m_strokeListとGetCurrentPen()の宣言や定義は手で書き込むようになっています。その理由は、これらが複雑なので、[変数の追加]や[関数の追加]がうまく使えないためでしょう。
3.StdAfx.hに#include <afxtempl.h>と書き込むのは、MFCのテンプレートクラスを使うときの約束です。この方法に従いましょう。
4.WizardBarを使うと目がまわりますが、まあ、慣れましょう。やっていることは手でやっても同じなのです。いろいろなことを一度に楽にやってくれているだけです。(くどい。くどすぎる。もう、この話は書きませんよ。)
5.CStrokeの説明はあまりいらないと思います。m_nPenWidthは線の太さを保持する変数です。使い方は後で分かってくるでしょう。また、シリアライズのためのお約束のコードが書かれていますが、忘れた人はVC入門13でも見ておいてください。

今回は第4章の途中で、フラストレーションがたまるかと思いますが、ここまでにさせてください。次回は、第4章後半(「ドキュメントの管理」から)としましょう。
目次のページ
前のページ
後のページ