WindowsAPI 文字表示


さて、せっかくウインドウを作ったわけですから、文字を表示させてみたいですよね。
真っ白なウインドウじゃつまんないですもんね(あなたが、白いウインドウマニアで「ウインドウ萌〜」なら別でしょうけど)
とにかく文字を出してみましょう。

〜文字を出す関数〜

文字を出す関数は

TextOut()

関数です。
printf()見たいなもんです。
これに文字を入れれば その文字が出るわけです。
簡単でしょ?

#include <windows.h>

LRESULT CALLBACK WndProc(HWND hwnd,UINT msg,WPARAM wp,LPARAM lp){

	HDC hdc;			//デバイスコンテキストのハンドルを入れておく変数。

	switch(msg){

		case WM_DESTROY:
			PostQuitMessage(0);
			return 0;

		case WM_LBUTTONDOWN:
			hdc = GetDC(hwnd);		//hwndのデバイスコンテキストのハンドルを取得
			TextOut(hdc,0,0,TEXT("hello"),5);	//文字を表示
			ReleaseDC(hwnd,hdc);	//さっきつくったデバイスコンテキストを解放。
			return 0;

		default:
			break;
	}

	return DefWindowProc(hwnd,msg,wp,lp);
}

int WINAPI WinMain(HINSTANCE hInstance,
			HINSTANCE hPrevInstance,
			PSTR lpCmdLine,
			int nCmdShow){

	HWND hwnd;
	WNDCLASS windowclass;
	MSG msg;

	windowclass.style		= CS_HREDRAW | CS_VREDRAW;
	windowclass.lpfnWndProc	= WndProc;
	windowclass.cbClsExtra	= 0;
	windowclass.cbWndExtra	= 0;
	windowclass.hInstance	= hInstance;
	windowclass.hIcon		= LoadIcon(NULL , IDI_APPLICATION);
	windowclass.hCursor		= LoadCursor(NULL , IDC_ARROW);
	windowclass.hbrBackground	= (HBRUSH)GetStockObject(WHITE_BRUSH);
	windowclass.lpszMenuName	= NULL;
	windowclass.lpszClassName	= TEXT("oyabunn");

	if(!RegisterClass(&windowclass))return -1;

	hwnd = CreateWindow(TEXT("oyabunn") , TEXT("こんちは世界!") ,
						WS_OVERLAPPEDWINDOW |WS_VISIBLE ,
						200 , 200 , 200 , 200 , NULL , NULL ,hInstance , NULL);
	
	while(GetMessage(&msg,NULL,0,0))DispatchMessage(&msg);

	return msg.wParam;
}


「簡単じゃないじゃないか!」と心の中で思ったでしょ?
世の中甘くないんだな〜。

ちなみにこれ実行すると な〜んにもない白いウインドウが出るでしょ?
ウインドウの中をクリックしてください。そしたら文字が出るはず。

では、解説。
新しいのが色々あるけど、結局文字を表示しているのは
TextOut(hdc,0,0,TEXT("hello"),5);
この部分です。
これが文字を表示する関数で、表示する場所と文字、そして文字の長さまで入れられます。
そこは簡単ですね。

問題は hdc が何者なのか。

これはデバイスコンテキストのハンドル なんですが、(またハンドルだね(^^;)
デバイスコンテキストってのは描画のためのデータが保存されているものです。
例えば こうしてあなたが見てるパソコンの画面も あるデバイスコンテキストにそのデータが
ばーっと入っていて それをディスプレイがただ出しているだけなのです。

イメージでいうと、、、
ペイントで書いた絵が そのままディスプレイに出るとしたら そのペイントの絵がデバイスコンテキストです。

だから画面に何か出したかったら、デバイスコンテキストに書き込めばいいことになるねっ。
ウインドウにはウインドウのデバイスコンテキストがあります。
だから、自分の作ったウインドウに文字を出したいときは
「自分のウインドウのデバイスコンテキストに文字を書けばいい!」

そのデバイスコンテキストのハンドルをゲットするのが。
GetDC関数。(ゲット デバイス コンテキスト関数)
使い方はこう。
hdc = GetDC(hwnd)
hwndにデバイスコンテキストが欲しい ウインドウのハンドルを入れることで、
そのウインドウのデバイスコンテキストのハンドルが手に入り 変数hdcに入ります。
そのために!これがあった。

HDC hdc;

これで デバイスコンテキストのハンドル(あ〜長い名前。キーボードうつのめんど)専用の 変数hdcをつくってたわけです。
そして、これにGetDCでウインドウのハンドルを代入して、そのハンドルを使って
TextOut(hdc,0,0,TEXT("hello"),5);
ここで、そのデバイスコンテキストに文字を描画している。

一度ゲットしたデバイスコンテキストは返さないと、DefWindowProcが使えなくなる(ウインドウを移動させたり出来なくなる)
ので、解放しなきゃいけません。なので
Release()関数でRelease(hwnd,hdc)でhwndのhdcを解放しています。

まとめると
㈰ウインドのデバイスコンテキストのハンドルを手にれる
 hdc = GetDC(hwnd);
㈪デバイスコンテキストに文字を描画する
 TextOut(hdc,0,0,TEXT("hello"),5);
㈫持ったままだとまずいのでデバイスコンテキストを解放する
 ReleaseDC(hwnd,hdc);


ってことです。
ただ、文字を出すタイミングをどうしようかと思って。
ウインドウ上でマウスを左クリックしたら WM_LBUTTONDOWN メッセージがでるので。それを使いました。
このメッセージが来たら(左クリックされたら)文字を出すようにしました。

もう1度見てみましょう

#include <windows.h>

LRESULT CALLBACK WndProc(HWND hwnd,UINT msg,WPARAM wp,LPARAM lp){

	HDC hdc;			//デバイスコンテキストのハンドルを入れておく変数。

	switch(msg){

		case WM_DESTROY:
			PostQuitMessage(0);
			return 0;

		case WM_LBUTTONDOWN:
			hdc = GetDC(hwnd);		//㈰hwndのデバイスコンテキストのハンドルを取得
			TextOut(hdc,0,0,TEXT("hello"),5);	//㈪文字を表示
			ReleaseDC(hwnd,hdc);	//㈫さっきつくったデバイスコンテキストを解放。
			return 0;

		default:
			break;
	}

	return DefWindowProc(hwnd,msg,wp,lp);
}

int WINAPI WinMain(HINSTANCE hInstance,
			HINSTANCE hPrevInstance,
			PSTR lpCmdLine,
			int nCmdShow){

	HWND hwnd;
	WNDCLASS windowclass;
	MSG msg;

	windowclass.style		= CS_HREDRAW | CS_VREDRAW;
	windowclass.lpfnWndProc	= WndProc;
	windowclass.cbClsExtra	= 0;
	windowclass.cbWndExtra	= 0;
	windowclass.hInstance	= hInstance;
	windowclass.hIcon		= LoadIcon(NULL , IDI_APPLICATION);
	windowclass.hCursor		= LoadCursor(NULL , IDC_ARROW);
	windowclass.hbrBackground	= (HBRUSH)GetStockObject(WHITE_BRUSH);
	windowclass.lpszMenuName	= NULL;
	windowclass.lpszClassName	= TEXT("oyabunn");

	if(!RegisterClass(&windowclass))return -1;

	hwnd = CreateWindow(TEXT("oyabunn") , TEXT("こんちは世界!") ,
						WS_OVERLAPPEDWINDOW |WS_VISIBLE ,
						200 , 200 , 200 , 200 , NULL , NULL ,hInstance , NULL);
	
	while(GetMessage(&msg,NULL,0,0))DispatchMessage(&msg);

	return msg.wParam;
}

ねっ?簡単でしょ?
結構毛だらけ猫灰だらけ、けつの・・・・・

〜おまけ〜

TextOut(hdc,0,0,TEXT("hello"),5);
の 最後の 5 ですが、表示する文字の量です。
ですが、いちいち自分で文字数を数えるのは面倒なので文字数を数える関数lstrlen()を使うと便利です。


#include <windows.h>

LRESULT CALLBACK WndProc(HWND hwnd,UINT msg,WPARAM wp,LPARAM lp){

	HDC hdc;			//デバイスコンテキストのハンドルを入れておく変数。

	switch(msg){

		case WM_DESTROY:
			PostQuitMessage(0);
			return 0;

		case WM_LBUTTONDOWN:
			hdc = GetDC(hwnd);		//hwndのデバイスコンテキストのハンドルを取得
			TextOut(hdc,0,0,TEXT("hello"),lstrlen(TEXT("hello")));	//文字を表示
			ReleaseDC(hwnd,hdc);	//さっきつくったデバイスコンテキストを解放。
			return 0;

		default:
			break;
	}

	return DefWindowProc(hwnd,msg,wp,lp);
}

int WINAPI WinMain(HINSTANCE hInstance,
			HINSTANCE hPrevInstance,
			PSTR lpCmdLine,
			int nCmdShow){

	HWND hwnd;
	WNDCLASS windowclass;
	MSG msg;

	windowclass.style		= CS_HREDRAW | CS_VREDRAW;
	windowclass.lpfnWndProc	= WndProc;
	windowclass.cbClsExtra	= 0;
	windowclass.cbWndExtra	= 0;
	windowclass.hInstance	= hInstance;
	windowclass.hIcon		= LoadIcon(NULL , IDI_APPLICATION);
	windowclass.hCursor		= LoadCursor(NULL , IDC_ARROW);
	windowclass.hbrBackground	= (HBRUSH)GetStockObject(WHITE_BRUSH);
	windowclass.lpszMenuName	= NULL;
	windowclass.lpszClassName	= TEXT("oyabunn");

	if(!RegisterClass(&windowclass))return -1;

	hwnd = CreateWindow(TEXT("oyabunn") , TEXT("こんちは世界!") ,
						WS_OVERLAPPEDWINDOW |WS_VISIBLE ,
						200 , 200 , 200 , 200 , NULL , NULL ,hInstance , NULL);
	
	while(GetMessage(&msg,NULL,0,0))DispatchMessage(&msg);

	return msg.wParam;
}


引数で渡した文字の文字数を返してきます。
lstrlenはstrlenに似てます。ただ、strlenは文字が保存されている容量を表しますがlstrlenは文字数だけです。
あいう は 3文字ですが 6バイトです。lstrlenで出てくるのは UNICODEが定義されてる限り3です。
今までのstrlenとは違うので注意ね。
TextOutではlstrlenの方を使います。

まとめ…

 画面やウインドウなど 描画情報が保存されているのは「デバイスコンテキスト」
 文字を出したければ
 1、そのハンドルを取得し
 2、デバイスコンテキストに文字を書き込み
 3、ハンドルを解放
 の操作で文字が出せるが、やってることは
 デバイスコンテキストに書き込みをしているだけ。

ホームへ