猫でもわかるWindowsプログラミング 第2版

タイマーを使ったスクロール

 プログラムの中で、一定時間ごとにある処理をしたい、という事が良くあります。 時計などはその典型でしょうし、他にも「時々」ある処理を実行する、 という場面は結構あるでしょう。そんな時に使うのが「タイマー」です。

・タイマー

 Windows のタイマーはSetTimer でセットされます。後は指定した時間毎にWM_TIMER メッセージが送られてくるようになるので、 ウインドウプロシジャー内でWM_TIMER メッセージを捕らえて処理すれば「一定時間毎」の処理が行えるわけです。
 SetTimer の引数は、 最初がメッセージを送るウインドウ、 2番目がタイマーのIDでこれは0以外の整数を指定し、 複数のタイマーを使用する時に個々のタイマーを識別するために使います。 そして、3番目の引数でメッセージを送る間隔をミリ秒単位で指定します。 最後の引数はタイマーが一定時間毎に呼び出す関数を指定できるのですが、 タイマーの処理をメッセージ処理で行う場合はNULL を指定しておけば良いでしょう。

 SetTimer(hwnd,1,100,NULL);

 このようにすると約100ms 毎にhwnd で指定されたウインドウにWM_TIMER メッセージが送られるようになります。ただし、 このタイマーはあまり精度が良くない上にメッセージが送られるだけなので、 厳密にタイミングを取る必要がある処理には適していないかもしれません (他のメッセージの処理に時間がかかるとその間はWM_TIMER メッセージを処理できない)。

・DIBのスクロール

 今回は、 タイマーを使ってDIBをスクロール表示させるテストプログラムを作りました。 DIBはメモリの配列として扱えるので、 スクロールもメモリの内容を転送するだけで実現できます。
 具体的に大きさが縦横32ドットのフルカラーDIBを考えてみましょう。 まず、1ドットが3バイトなので(x,y) のドットは(x+y*32)*3 バイトからの3バイトに格納されている事になります。 では、このDIBを1ドット下に「ずらす」には、 言い換えれば縦方向の2列目から一番上の32列目までを、 1列目から31列目までに持ってくるにはどうすれば良いでしょうか? そう、答えは「2列目の最初である97バイト目から最後まで までの32*(32ー1)*3=2976バイトを1列目の最初(要するに1バイト目) から2976バイト目までに持ってくる」ですね。 このあたりは、文章だとわかりにくいでしょうがDIBの構造を図に描いてみれば、 すぐに理解できるでしょう(DIBの構造は前回を参照)。
 実際にプログラムする時は、メモリを移動するMoveMemory

 MoveMemory(lpBit,lpBit+xSize*3,xSize*(ySize-1)*3);

 などとします。これで、大きさが横xSizeで縦ySize(ただし共に4の倍数)、 バッファの最初がlpBit のフルカラーDIBの絵を1ドット下にずらせるわけです。

 プログラムでは、ランダムにドットを打ったDIBを用意して、 スクロールさせるごとに一番上のラインに新たにドットを打つようにしました。

case WM_TIMER: // タイマーメッセージの処理

	MoveMemory(lpBit,lpBit+xSize*3,xSize*(ySize-1)*3); // スクロール
	ZeroMemory(lpBit+(ySize-1)*xSize*3,xSize*3); // 一番上の列をクリア

	n=rand() % 3+4; // ドットの数

	for (i=0;i<n;i++){ // 一番上の列にドットを打つ

		x=rand() % xSize;

		r=rand() % 64+192;
		g=rand() % 64+192;
		b=rand() % 64+192;

		lpBit[((ySize-1)*xSize+x)*3]=b;
		lpBit[((ySize-1)*xSize+x)*3+1]=g;
		lpBit[((ySize-1)*xSize+x)*3+2]=r;

	}

	InvalidateRgn(hwnd,NULL,FALSE);
	UpdateWindow (hwnd);             // 再描画

	return 0;

プログラムソース表示
戻る