VC++5.0入門21
チュートリアル読書会3 98/2/15

こんにちは。
まず、「CScribbleDoc のメンバ関数とメンバ変数のまとめ」をもう一度見てみましょう。ここにある変数と関数は自動でかあるいはWizardを使ってか、あるいは手動で、すでにファイルに(基の部分は)書き込まれているはずです。ちょっと思い出して下さい。
私がはじめてチュートリアルを読んだときには、とても混乱しました。関数や変数の書き込み方がいろいろあって、そこにWizardだのなんだのと、、、と思ったものです。ここで、いくつか確認しておいた方が良いかもしれません。

 全体像がわかるのは次の章のビューの記述が終わってから。したがって、今わからないのは、当然である。解説は後の方にある。(何度も言っていますね。)

それはともかく、
関数には種類がある。
 OnNewDocumentは、AppWizardが(基の部分を)生成してくれる特別な関数。
 (「基の部分」と書いたのは、これから書き換えをするからです。他の関数についても同様です。)
 OnOpenDocumentは、AppWizardは生成してくれないが、もともと名前の決まっている特別な関数。
 DeleteContentsも同じ。
 (上の3つの関数は、CScribbleDocの基底クラスCDocumentですでに用意されているのです。)
 InitDocumentは、チュートリアルの作者が勝手に考えた関数。
 GetCurrentPen、NewStrokeも同じ。
ということを見ておきましょう。よく思い出してみると、上の関数は種類に応じて3種類の(基の部分の)書き込み方法があったと思います。(正確には、OnNewDocumentは自動で生成されるのでした。)
まず、3つの特別な関数について説明しましょう。
普通のアプリケーションには、メニューというものがあり、メニューの左端には「ファイル」という項目があり、その中には、「新規作成」と「開く」があります。AppWizardを使ったMFCプログラムでは、自動でこのようなインターフェースが付けられるようになっていますね。(スケルトンの実行で見たはずです。)
実は、メニューで「ファイルを新規作成」を選ぶと呼び出されるのが、OnNewDocumentなのです。(誰が呼び出すんでしょう?フレームワークです。この言葉を覚えていた人は優秀です。「フレームワークが呼び出す」とはつまり「自動で呼び出される」ということです。)この関数は(普通の)MFCの枠組みでは絶対に必要なので、AppWizardが基を書いてくれるのです。
また、「ファイルを開く」が選択されるときに呼び出されるのがOnOpenDocumentです。これも大抵のアプリで必要なので、はじめから名前は決まっているのです。しかし、いつも必要とは限らないので、AppWizardは書いてくれないのです。
DeleteContentsも特別な関数で、「ファイルの新規作成」などの際に、古いデータ(ドキュメント)を破棄するために呼び出される関数です。この関数を書き込まなければ、古いデータは破棄されないということになります。まあ、それでも良いという人がいそうなので、やはりAppWizardが自動生成してくれないのです。(たぶんね。)
さて、似たような名前のInitDocumentは特別な関数でもなんでもありません。紛らわしいですね。ただ、MFCチュートリアルの作者は(たぶん)次のように考えたのです。

このアプリ(Scribble)では、「新規作成」も「開く」もほとんど同じ事をする。(以下参照)それなら、同じところをひとつの関数にして、OnNewDocumentとOnOpenDocumentでは、この関数を呼び出すことにしよう。さて、その関数にはInitDocumentという名前をつけるかな。

まあ(^^;)こんな感じでしょう。これはC++(やC)では当然/健全な発想です。(つまり、「同じコードを書くな」というルールに従っているのです。)そういうわけなので、混乱しないでください。

ちょっと、チュートリアルを見てみましょうか。InitDocumentの定義が、
    m_nPenWidth = 2;
    m_penCur.CreatePen(PS_SOLID, m_nPenWidth, RGB(0,0,0));
などと書かれていると思います。まず、m_nPenWidthというのは一筆(ストローク)の筆の幅でしたね。これを、まず、2ピクセル分とするのです。もちろん、後で変更したりするのですが、今回は、ここで2と設定するんだな、と理解してください。「ピクセル」というのは「画面上の点」を表すものと思ってください。)
m_penCurは、一筆に使うペンを表している、と前回書きましたが、まず、そのペンを「作る」必要があります。それが、2行目です。(オブジェクトを生成しただけでは、「ペン」にならないのです。)PS_SOLIDはこれが普通のペンであることを意味しています。もちろん、m_nPenWidthはペンの幅ですね。最後の引数RGB(0,0,0)は、このペンが黒であることを意味しています。
これにはちょっと説明が必要かもしれません。普通、色は3つの色、赤(Red)、緑(Green)、青(Blue)の混ぜあわせとして表現されます。そして、それぞれの色に256段階の強さがあり、その強さは0から255までの数字で表されます。
それで、例えば、RGB(255,0,0)はRedが255(最強)、GreenとBlueは0という意味で、(明るい)赤を表します。同様にRGB(0,255,0)は緑、RGB(0,0,255)は青です。また、RGB(255,0,255)とすると、赤+青つまり紫です。RGB(0,0,0)はすべての色が無いので黒です。ちなみに、RGB(255,255,255)はなんでしょう。すべての色を混ぜているので、、、そう、白ですね。昔、3原色をまぜると、、、なんてやりましたよね。
もちろん、いろいろな組み合わせの色ができますが、画面の設定がフルカラーになっていないと、それに近い色にしかなりません。注意して下さい。

このInitDocumentがOnNewDocumentとOnOpenDocumentで使われるのですね。

DeleteContentsについては、もう、説明はいらないでしょう。

はじめてチュートリアルを読んだ時に、私がこの辺で一番悩んだのは、NewStrokeという関数であったような気がします。この関数は名前の通り(?)、CStrokeを生成する関数です。ちなみに、私のNekoプロジェクトでは、対応する関数を作りませんでした。この関数は絶対必要というわけではなく、Nekoでやったように、同じ事を必要な場所(Nekoなら、NekoのビューのOnLButtonDown)にべたっと書いても、まあ、いいのです。ただ、このように関数を作る方が、ずっと良いやり方です。
前置きはそれぐらいとして、NewStrokeの中身ですが、これはNekoのビューのOnLButtonDownの中身とほぼ同じ内容のものを関数として定義しているのです。注意することはCStrokeのコンストラクタがペンの幅を決めるのにintの引数を持っている(CStrokeの定義部分を見直してください)ことでしょうか。エッセンスは、この関数が、CStrokeを生成し、そのオブジェクトへのポインタをm_strokeListに付け加え、そのポインタ(アドレス)を戻しているということです。どう利用するかがわからないと、なんだかわからない関数ですが、ご想像の通り、CScribbleView::OnLButtonDownで使われます。それはそのとき見てみましょう。

チュートリアルの残りの部分は、シリアライズの話ですね。シリアライズとは、データの書き込みと読み出しを表しています。これについては、VC入門13で説明したので、今回は許して下さい。

UINTとかWORDの定義も説明した方が良いかもしれません。本当はそろそろヘルプを見られるようになっていると良いのですが、一応、書きましょう。UINTは符号無しの整数を表しますが、許される値の範囲が場合によって違うというやっかいな性質を持っています。WORDは16ビットの符号無し整数のことです。16ビットってなんだと思った人は、とりあえず、許される値の決まっている符号無し整数と思っておけば良いでしょう。

できるかぎり、週1回のペースでアップしていきたいのですが、来週以降ちょっとあやしいです。気長に読んでください。
目次のページ
前のページ
後のページ