Version 9.16
文字列の横幅縦幅
「前回はテキストエディタもどきを作りました」
『あれだけでも結構カッコイイよねー、漢字もちゃんと入るし。プログラム
も簡単だったし』
「簡単だったけど、ちょっといろんなところを修正したから、今回もう一度
まとめるね。まず、再描画をするプログラムの場合、入力するたびにこうい
う手順を踏みます」
1:入力すると入力ハンドラが呼ばれる。
文字入力なら CSdiTestView::OnChar() 。
2:入力されたデータをメンバ変数に取っておく。
CSdiTestView::OnChar() の第1引数に入力文字が入ってる。
それをメンバ変数 m_cMainTextStr に追加する。
3:InvalidateRect() で再描画を指示する。
4:再描画の指示を受けて CSdiTestView::OnDraw() が呼ばれる。
5:メンバ変数からデータを取ってくる。
m_cMainTextStr にこれまでに追加された文字列が入ってるのでそれを。
6:それを描画する。
描画先は CSdiTestView::OnDraw() の引数に渡される DC 。
「あ、前回よりもう少し詳しく書いてあるから」
『こういうふうに細かく書くと、結構面倒な感じよねー。でもプログラム的
には量多くなかったよね』
「うん、まず SdiTestView.h の方に」
class CSdiTestView : public CView
{
// 描画する文字列。
CString m_cMainTextStr; // 追加。
// 略。
「って感じにメンバ変数を追加。これが1」
『この中に、入力された文字列ぜーんぶ入ってるわけね』
「次に、キー入力時のハンドラ CSdiTestView::OnChar() で、入力された文
字をこの中に追加します」
void CSdiTestView::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
{
// メンバ変数に入力した文字を追加。
m_cMainTextStr += nChar;
// 再描画を指示。
InvalidateRect( NULL );
CView::OnChar(nChar, nRepCnt, nFlags);
}
「これが2と3」
『文字を追加して、んで再描画の指示ね。あれ? そういえば、前に
InvalidateRect() を使った時ってこんな簡単だったっけ』
「 Version 7.16 ( No.136 ) の時は API だったけど、これはメンバ関数だ
から。実際に呼んでるのは CWnd::InvalidateRect() 」
『 CWnd のメンバ関数?』
「さっきの SdiTestView.h を見てもらえば分かるけど、 CSdiTestView
って CView から継承してるでしょ」
『継承って……』
「 Version 2.13 ( No.024 ) 参照」
『あ、継承してるとそのメンバ関数は全部使えるんだよね』
「で、リファレンス見れば分かるけど CView は CWnd から継承してるから」
『 CWnd::InvalidateRect() が使えるわけね。なんかその辺って忘れちゃい
そう』
「これからは重要になるから……まぁそれから憶えてもいいし。それに」
『それに?』
「フレームウィンドウもビューウィンドウもウィンドウなんだから、当然
CWnd から派生してる、って憶えてもいいし」
『……なんかそれってテキトーじゃない?』
「適当だけど、 MFC はその辺はある程度理屈通ってるから大丈夫だよ」
『確かに理屈は通ってるよね、ウィンドウだから CWnd ……』
「と、話を戻して。再描画の指示を出したら、再描画用のハンドラが呼ばれ
るからそこで再描画します」
void CSdiTestView::OnDraw(CDC* pDC)
{
CSdiTestDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
// これまでに入力された文字列を出力。
pDC->TextOut( 0, 0, m_cMainTextStr );
}
「これが5と6になります」
『質問!』
「はい火美ちゃん」
『まず、』
CSdiTestDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
『ってなに?』
「これはあと3回くらい後に説明するから、それまではおあずけ」
『別におあずけってほど聞きたいわけじゃないけど。次の質問! なんか再
描画のたびにちかちかするんだけど』
「あ、たぶんウィンドウを小さくして入力すればあまりしないよ」
『あ、ホントだ』
「大きくするとダメだけど」
『う”、これってじゃあ最大化ってできないじゃん。なんで?』
「これは、再描画って実は結構大変だから。ビューウィンドウを一度全部消
して全部描き直しってすると、結構処理に時間がかかるから、消してから次
のを描くまでに時間がかかって」
『だからちかちかしちゃうのね』
「この辺をちゃんと考える場合には、本当に更新される部分だけ更新したり
とかって処理が必要かな」
『? それってどうやるの?』
「 InvalidateRect() って更新できる範囲を変えられたでしょ」
『あー。でも……入力された文字が画面上のどこに出るのかってわかる
の?』
「それは大丈夫。ちょっと試してみようか」
void CSdiTestView::OnDraw(CDC* pDC)
{
CSdiTestDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
// これまでに入力された文字列を出力。
pDC->TextOut( 0, 0, m_cMainTextStr );
// 以下追加。
// 文字列が入る四角を取得。
CSize cSize = pDC->GetTextExtent( m_cMainTextStr );
TRACE( "%d, %d\n", cSize.cx, cSize.cy );
}
「この最後の3行を追加して」
『 CDC::GetTextExtent() ってメンバ関数呼んでるね』
「これは、渡された文字列を書き込んだときの横幅と縦幅を取得する関数。
とりあえず試してみて」
『ほい。お』
8, 18
16, 18
24, 18
32, 18
『って増えてく!』
「左が横幅、右が縦幅」
『そっか、文字の数が増えれば横幅は増えてく、でも縦は変わらないわけ
ね』
「ちなみに CSize はこういう横幅と縦幅を持つためのクラス。 CRect や
CPoint とかと同じ種類のクラスだから」
『ただデータ入れるためだけのってわけね。質問!』
「はい火美ちゃん」
『このメンバ関数って、なんでデバイスコンテキストが必要なの?』
「 Version 7.13 ( No.133 ) でやったように、フォントのサイズ種類やサ
イズってデバイスコンテキストに登録してから使うでしょ」
『あ! そっか、そういうのが決まらないとサイズも決まらないんだ』
「ここで取得してるサイズは、そのデバイスコンテキストが今持ってるフォ
ントのもの。だから別のフォントのを取得するときには」
『別のフォントをデバイスコンテキストに持たせてからこれ呼ぶわけねー』
「たとえば、今は横幅って8ずつ一定に増えてるでしょ」
『そういえば、プロポーショナルフォント、だっけ、あれだと横幅って一定
じゃないよね』
「そう、そういうときにはフォントの種類も重要だから」
『そういうのをちゃんとセットしてから取得する必要があるわけね』
「漢字だとまた違ってくるし」
『あ、ちゃんと漢字の時のサイズも分かるんだね。あ! もひとつ質問!』
「はい火美ちゃん」
『改行がうまくいかないけどなんで!? 文字列の縦幅は変わらないし、画
面も黒いのが表示されるだけだし』
「これは色々理由があるんだよね。まず、 CDC::GetTextExtent() は改行は
無視するから」
『げ、それってめんどくない?』
「面倒じゃないよ。文字の高さはプロポーショナルフォントでも文字毎に違
うことはないから、普通に1行分取得して、行数だけ増やせば」
『でも、今何行あるかとかわかんないじゃん』
「あ、その辺になるんだね……その辺はもうちょっとあとで。とりあえず計
算すれば高さは分かるってことで。あともうひとつ。えーっと」
void CSdiTestView::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
{
// メンバ変数に入力した文字を追加。
m_cMainTextStr += nChar;
// 再描画を指示。
InvalidateRect( NULL );
// 文字コードを16進表示。
TRACE( "%X, %X\n", nChar, '\n' ); // ここ追加。
CView::OnChar(nChar, nRepCnt, nFlags);
}
「って修正して、リターン押してみて」
『ほい。あ』
D, A
『改行じゃない……って、どういうこと? リターン押したら \n が送られ
て来てないってこと??』
「そう、正確に言うと \r が送られてきてるんです」
『な、なにそれ……』
「それに、デリートキーやカーソルキーも効かないでしょ」
『そういえば CSdiTestView::OnChar() が呼ばれない……』
「というわけで続く!」
/*
Preview Next Story!
*/
『改行なのに改行じゃない!? いったいなんなのー!?』
「そこには複雑な話が隠されているのです」
『複雑はイヤー!』
「でも、これは避けて通れない道だから」
『仕方ないのね……』
「ちなみにそういう道がいっぱいあります」
『へ?』
「というわけで次回」
< Version 9.17 キー入力の秘密 >
『につづく!』
「来週はプログラマー辞めたくなるかもよ?」
『辞めてもいい?』
「せめて連載が終わるまではがんばって」
『うう……』