Version 10.20
SDK だけで作るテキストエディタもどき
「さて、 SDK 編最後はテキストエディタもどきです」
『 Version 9.15 ( No.176 ) で MFC 使ってやった部分ね』
「そう、あれを SDK だけで作ってみます。 SDK だけで作る分、簡単なとこ
ろもあるし、難しい所もあるから」
『ツールバーやステータスバーもそうだったものね』
「では、まずキー入力を受け取るようにします」
『 Version 10.06 ( No.184 ) でやったのだね』
「具体的にはこうします」
// ウィンドウプロシージャ。
LRESULT CALLBACK WndProc
( HWND p_hWnd
, UINT p_uiMessage
, WPARAM p_wParam
, LPARAM p_lParam
)
{
if( p_uiMessage == WM_CREATE )
{
return OnCreate( p_hWnd, p_wParam, p_lParam );
}
else if( p_uiMessage == WM_DESTROY )
{
return OnDestroy();
}
else if( p_uiMessage == WM_RBUTTONUP )
{
return OnRButtonUp( p_hWnd, p_wParam, p_lParam );
}
else if( p_uiMessage == WM_COMMAND )
{
if( LOWORD( p_wParam ) == ID_MENU_TEST )
{
return OnMenuTest( p_hWnd, p_wParam, p_lParam );
}
}
else if( p_uiMessage == WM_CHAR )
{
return OnChar( p_hWnd, p_wParam, p_lParam );
}
// 標準的な処理をします。
return DefWindowProc( p_hWnd, p_uiMessage, p_wParam, p_lParam );
}
『おなじみ WM_CHAR だね』
「もちろん、本格的なテキストエディタにするなら WM_KEYDOWN とかにも対
応しないといけないけどね」
『カーソルキーとか使えないもんね。……そういえば』
「そういえば?」
『この WM_CHAR が使えるのって TranslateMessage() 使ってるからだよね』
「そう、この API が WM_KEYDOWN とかを WM_CHAR に変換してるから」
『……その時点で SDK の方が面倒じゃん』
「でも、メッセージループなんて一度作っちゃったら他のプログラムでも使
い回せるよ?」
『あ、そういえば』
「で、それの大がかりなのが MFC ってこと」
『ぇ?』
「 MFC のメッセージループだって、他の誰かが作ったメッセージループ
ってだけで、それを使い回してるのは同じってこと」
『あ……そういう意味じゃ、あたしが作ったメッセージループをあたしが使
い回しても、 MFC のメッセージループを使っても同じなんだ』
「そういうこと。 MFC みたいな大きなライブラリを使ってると構えちゃう
かもしれないけど、そんなに難しく考える必要はないから」
『でもやっぱレベル違うし……』
「まあね……で。この WM_CHAR が送られてきた時に呼ばれる関数 OnChar()
は、次のような感じ」
// キー入力がありました。
LRESULT OnChar
( HWND p_hWnd
, WPARAM p_wParam
, LPARAM p_lParam
)
{
char pch[256];
sprintf( pch, "%c", (char)p_wParam );
OutputDebugString( pch );
return 0;
}
『 MFC の時は TRACE() だけだったのに……』
「 Version 5.07 ( No.072 ) でやったでしょ、 TRACE() と同じに使える
って」
『あー』
「 TRACE() の変わりに、文字を文字列に変換するのに sprintf() を、アウ
トプットウィンドウに出力するのに OutputDebugString() を使ってます」
『ってことは、キーは p_wParam に入ってるんだ』
「そういうこと。とりあえずここで試してみて」
『ほい。おー、アウトプットウィンドウにキーが出る! あの時と同じ〜』
「では次に、再描画の部分を作ります。二度手間になっちゃうけど、ウィン
ドウプロシージャをもう一度修正して」
// ウィンドウプロシージャ。
LRESULT CALLBACK WndProc
( HWND p_hWnd
, UINT p_uiMessage
, WPARAM p_wParam
, LPARAM p_lParam
)
{
if( p_uiMessage == WM_CREATE )
{
return OnCreate( p_hWnd, p_wParam, p_lParam );
}
else if( p_uiMessage == WM_DESTROY )
{
return OnDestroy();
}
else if( p_uiMessage == WM_RBUTTONUP )
{
return OnRButtonUp( p_hWnd, p_wParam, p_lParam );
}
else if( p_uiMessage == WM_COMMAND )
{
if( LOWORD( p_wParam ) == ID_MENU_TEST )
{
return OnMenuTest( p_hWnd, p_wParam, p_lParam );
}
}
else if( p_uiMessage == WM_CHAR )
{
return OnChar( p_hWnd, p_wParam, p_lParam );
}
else if( p_uiMessage == WM_PAINT )
{
return OnPaint( p_hWnd, p_wParam, p_lParam );
}
// 標準的な処理をします。
return DefWindowProc( p_hWnd, p_uiMessage, p_wParam, p_lParam );
}
「 WM_PAINT の部分を追加しました」
『あ、そっか、 MFC で使った OnDraw() ってないんだよね』
「そう、本当は再描画するときは WM_PAINT が送られてきて、 MFC はその
時に OnDraw() を呼んでました。で、 SDK の方は代わりに OnPaint()
って関数を作って呼ぶようにします。それがこれ」
// 再描画します。
LRESULT OnPaint
( HWND p_hWnd
, WPARAM p_wParam
, LPARAM p_lParam
)
{
PAINTSTRUCT stPaintStruct;
HDC hDC
= ::BeginPaint
( p_hWnd
, &stPaintStruct
);
const char pchText[] = "あいうえお";
TextOut
( hDC
, 0
, 28
, pchText
, strlen( pchText )
);
::EndPaint
( p_hWnd
, &stPaintStruct
);
return 0;
}
『あれ、これってどっかでみたよーな』
「 Version 7.15 ( No.135 ) と同じだよ」
『あ! そっか、ダイアログでデバイスコンテキスト使ったときのと同じな
んだ』
「ダイアログだと MFC のシステムが備わってなかったから、 SDK と同じ方
法で描画したんです。だからあの時と同じ」
『でもちょっと違うよね』
「あの時はスタティックコントロールのウィンドウハンドルを使ったけど、
今回はウィンドウプロシージャのをそのまま使ってるから」
『 p_hWnd ね。それより……』
TextOut
( hDC
, 0
, 28
, pchText
, strlen( pchText )
);
「の 28 っていうのが気になるんだけど」
『それは次回に続く!』
「ええっ!?」
/*
Preview Next Story!
*/
『 28 って謎な数字』
「こういうのって難しいんだよね」
『何が?』
「本当はこういうふうに直に書くのはいけないんだけど」
『だよね。前にそんなのきいたよーな』
「でも、最初に教える時はこういう具体的な数字の方が解りやすいから」
『ならそっちの方がいいじゃん』
「というわけで次回」
< Version 10.21 ツールバーとクライアントエリア >
『につづく!』
「でもさ、これで次回見なかったりされると困る……」
『いるの?』
「毎週しっかり読むのは大変じゃないかな」
『確かに……』