Version 9.15
ちょっとテキストエディタっぽく!
「今回からは、ビューウィンドウに描画してみます」
『あ、そういえばそれって全然してなかったね』
「ビューはマウスとかの入力を受けるためのものだけど、同時に表示をする
ためのものだから、両方ともできないとね」
『入力って、前に右クリックメニュー作ったときみたいに?』
「そうそう、それが入力。で、今度はそれに対する出力ってことだね」
『簡単?』
「デバイスコンテキストって憶えてる?」
『うん、画面に描くときに……そっか! ビューでもそれは変わんないん
だ!』
「そゆこと。デバイスコンテキストについては Version 7.01 ( No.121 )
を読み返してもらうとして、さっそくやってみようか。えっと、
Version 9.05 ( No.166 ) のままなら、右クリックしたときのメンバ関数
ってこうなってるよね」
void CSdiTestView::OnRButtonUp(UINT nFlags, CPoint point)
{
// 画面上のマウスカーソルの位置を取得します。
CPoint cPoint;
GetCursorPos( &cPoint );
// フレームウィンドウのポインタを取得します。
CWnd *pcMainFrameWnd
= AfxGetMainWnd();
// メニューバーを取得します。
CMenu *pcMenuBar = pcMainFrameWnd->GetMenu();
// 「ファイル」サブメニューを取得します。
CMenu *pcFileMenu
= pcMenuBar->GetSubMenu( 0 );
// ポップアップメニューを表示します。
pcFileMenu->TrackPopupMenu
( TPM_LEFTALIGN | TPM_TOPALIGN | TPM_LEFTBUTTON
, cPoint.x
, cPoint.y
, pcMainFrameWnd
);
CView::OnRButtonUp(nFlags, point);
}
『うん。右クリックメニューのだよね』
「この時と同じように、あるイベントのメンバ関数を作ってもらいます」
『ハンドラってやつよね。で、なんの?』
「キー入力の」
『お! なんかちょっとすごそう』
「すごくはないと思うけど……メッセージは WM_CHAR 」
『それはべたね。作り方は右クリックの時と同じ?』
「同じで大丈夫」
『んじゃ ClassWizard 開いて〜 CSdiTestView を選んで WM_CHAR でメンバ
関数作って編集っと』
void CSdiTestView::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
{
// TODO: この位置にメッセージ ハンドラ用のコードを(略)
CView::OnChar(nChar, nRepCnt, nFlags);
}
『って感じにできました』
「これが MFC が用意してくれた WM_CHAR のハンドラ関数。この第1引数に
押された文字が入ってます。というわけで、次のように修正して」
void CSdiTestView::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
{
TRACE( "%c", nChar );
CView::OnChar(nChar, nRepCnt, nFlags);
}
『 %c ?』
「 Version 5.04 ( No.069 ) でやったよ」
『あ、文字の時はこれなのね。んじゃビルドして実行! おお! キーボー
ド叩くとアウトプットにその文字が! ちょっと感動……』
「この文字を、実際にビューに表示させるとエディタっぽくなるわけだね」
『やってみたい!』
「じゃあやってみましょう。文字列を表示させる方法は Version 7.12
( No.132 ) 、 MFC 版は Version 7.14 ( No.134 ) を参照」
『やっぱデバイスコンテキストを使うわけね』
「ですが!」
『ですが?』
「ここから先は、ダイアログの時とは違う、ビューウィンドウ専用の処理方
法になります」
『ビュー専用?』
「そう。 Version 7.15 ( No.135 ) でやった再描画ってあるでしょ」
『画面が消えるとデバイスコンテキストに描いた内容も消えちゃうってゆー
のだよね』
「ビューにはその再描画を簡単にする仕組みがあるんです。こういうメンバ
関数があるでしょ」
void CSdiTestView::OnDraw(CDC* pDC)
{
CSdiTestDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
// TODO: この場所にネイティブ データ用の描画コードを追加します。
}
『お、いつの間に』
「これは最初から用意されてるメンバ関数。再描画されるときにこのメンバ
関数が呼ばれるから、その中で再描画するようにすればいいわけ」
『あ! 引数に CDC ってある! もしかしてこれで描画できちゃうの?』
「そう、このデバイスコンテキストはビューウィンドウのだから、これに対
して描画すればいいわけ」
『いたれりつくせりねー。……あれ? でもさ、再描画って OnPaint()
ってメンバ関数でするんじゃなかったっけ』
「お、いいとこ突いてるかも。実はこの CSdiTestView::OnDraw() は
CView::OnPaint() から呼ばれてるんです。試しに CSdiTestView::OnDraw()
の中にブレークポイント置いて」
『ほい。ビルドして実行あっとすぐ止まっちゃった』
「再描画って言っても、最初に表示されるときにも」
『再描画なわけね。で?』
「ステップアウトのボタン……ツールバーの〈中カッコから出る〉ってアイ
コンのボタンを押して。それ押せば CSdiTestView::OnDraw() を呼んだ関数
に戻るから」
『ほいほい。お!』
void CView::OnPaint()
{
// standard paint routine
CPaintDC dc(this);
OnPrepareDC(&dc);
OnDraw(&dc);
}
『なるほどねー、まず CView::OnPaint() が呼ばれて、その中で
CSdiTestView::OnDraw() が呼ばれてるわけね』
「つまり OnDraw() は何かのメッセージのハンドラじゃなくて、ビュークラ
スの〈再描画用メンバ関数〉ってこと。 OnPaint() だと BeginPaint() と
かが必要で面倒だから、それを CView::OnPaint() に隠してるんです」
『あ、そういえば BeginPaint() と EndPaint() がないよ?』
「この中で CPaintDC ってクラス使ってるでしょ。このクラスがそれを代わ
りにしてくれるんです」
『へーっ、便利ねー』
「ま、この辺は楽屋裏ってことで、実際に描画する部分を見てみようか。
描画は CSdiTestView::OnDraw() でするから、その中で文字列を描画させる
と……」
void CSdiTestView::OnDraw(CDC* pDC)
{
CSdiTestDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
pDC->TextOut( 0, 0, "あいうえお" );
}
『うんうん、これは前やったのと同じ感じ』
「分かりやすいでしょ。こうやって、デバイスコンテキストさえ取得できれ
ば、相手を気にすることなく描画できるわけ」
『その辺は便利よねー。……でもさ、これってさっきのキー入力と全然関係
ないじゃない』
「もちろん。 Version 7.16 ( No.136 ) を読み返してもらえば分かるけ
ど、再描画を踏まえた描画の場合には」
1:入力ハンドラで、入力データをメンバ変数に取っておく。
2:InvalidateRect() で再描画を指示する。
3:OnDraw() が呼ばれるから、メンバ変数からデータを取ってくる。
4:それを描画する。
「っていうステップが必要になります」
『……よーするにめんどいわけね』
「そうでもないよ。まず、入力した文字をメンバ変数に取っておくところか
ら。 SdiTestView.h の方に」
class CSdiTestView : public CView
{
// 描画する文字列。
CString m_cMainTextStr; // 追加。
// 以下略。
「って感じに追加して」
『文字列は CString に入れるわけね』
「そゆこと。ここで作った m_cMainTextStr は CSdiTestView のメンバ変数
だから、 CSdiTestView のどのメンバ関数からも使えます。というわけで
CSdiTestView::OnChar() を次のように修正」
void CSdiTestView::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
{
// メンバ変数に入力した文字を追加。
m_cMainTextStr += nChar;
// 再描画を指示。
InvalidateRect( NULL );
CView::OnChar(nChar, nRepCnt, nFlags);
}
『 m_cMainTextStr に入力した文字を入れてく……ってのは分かるけど、
+= なんかで入るの?』
「うん、そういう機能が CString に備わってるからね。で、追加したら再
描画を指示すると」
『 OnDraw() が呼ばれるわけね』
「そゆこと。で、そっちは」
void CSdiTestView::OnDraw(CDC* pDC)
{
CSdiTestDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
// これまでに入力された文字列を出力。
pDC->TextOut( 0, 0, m_cMainTextStr );
}
「さっき〈あいうえお〉だったのがメンバ変数のになっただけだから」
『ビルドして実行……おおっ! 打ったらすぐ出る! なんか、なんかホン
トにエディタっぽい!!』
「結構簡単にこれくらいはできるってことだね」
/*
Preview Next Story!
*/
『エディタっ、ちょっとカッコイイ!』
「まぁ、本格的なエディタには叶わないけどね」
『 VC のとか?』
「秀丸エディターとかもね」
『そのくらいできるようになるにはどのくらいかかる?』
「無理」
『へ?』
「というわけで次回」
< Version 9.16 文字列の横幅縦幅 >
『につづく!』
「いや、このレベルのエディタは普通には作れないから……」
『……そうよね、あたしは水希ちゃんを超えることはできないのよね』
「……むかつくけど言い返せない……」