メモリデバイスコンテキスト

使う関数

メモリデバイスコンテキストとは、メモリ上のデバイスコンテキストです。
前回やったDCが実際の画用紙なら、メモリDCは下書きのように考えてください。
下書きなので、誰にも見られることはありません。
メモリDCを使うことで、実際の描写処理を楽にすることができます。
WM_PAINTがくるたびにDCに実際の描写をしなくても、いったんメモリDCに描いておいて、それを実際のDCにコピーすればいいからです。
メモリDCは、以下の関数を使って作成します。
CreateCompatibleDC(関連するDC) As HDC
CreateDCで作る方法がありますが、面倒なので手を出さないほうが無難です。

CreateCompatibleDCで作ったDCは1×1のモノクロビットマップです。使えない画用紙しか持っていません。
なので、自分で大きな画用紙を作ります。
CreateCompatibleBitmap(関連するDC , xサイズ , yサイズ) As HBITMAP
でビットマップハンドルが返ります。またハンドルが出てきますが我慢しましょう。
画用紙のコピーはBitBltかStretchBltです。今回は簡単なBitBltを使います。
BitBlt( _
    受け側DC , 左上x , 左上y , 幅 , 高さ , _
    送り側DC , 左上x , 左上y ,合成モード) As Long
合成モード、正式にはラスタオペレーションといいます。

作る

実際にやります。プロジェクトを作ります。
今回はボタン(ID:IMAGE)とイメージボックス(ID:ImageBox1、200*200サイズ)を貼り付けます。
次に、必要な変数を外部変数で宣言します。(TODOのところ)
ウインドウが作られたとき(WM_CREATE)に、初期設定を行います。
ボタンが押されたときに、メモリDCお絵かきします。
WM_PAINTのとき、BitBlt関数でメモリDCの表示を行います。
以下コードです。MainWnd.sbpをそのまま載せます。
'-----------------------------------------------------------------------------
'  イベント プロシージャ
'-----------------------------------------------------------------------------
' このファイルには、ウィンドウ [MainWnd] に関するイベントをコーディングします。
' ウィンドウ ハンドル: hMainWnd

' TODO: この位置にグローバルな変数、構造体、定数、関数を定義します。
#include<vcrt71.sbp>
Dim hImgDC As HDC'イメージボックスのDC
Dim hMemDC As HDC'メモリDC
Dim hBmp As HBITMAP'メモリDC用ビットマップ
'-----------------------------------------------------------------------------
' ウィンドウメッセージを処理するためのコールバック関数

Function MainWndProc(hWnd As HWND, dwMsg As DWord, wParam As WPARAM, lParam As LPARAM) As DWord
    ' TODO: この位置にウィンドウメッセージを処理するためのコードを記述します。

    ' イベントプロシージャの呼び出しを行います。
    MainWndProc=EventCall_MainWnd(hWnd,dwMsg,wParam,lParam)
End Function


'-----------------------------------------------------------------------------
' ここから下は、イベントプロシージャを記述するための領域になります。

'これは終了時に呼ばれます。ここで作ったものを開放します。
Sub MainWnd_Destroy()
    DeleteObject(hMemDC)
    DeleteObject(hBmp)
    ReleaseDC(GetDlgItem(hMainWnd , ImageBox1) , hImgDC)
    test_DestroyObjects()
    PostQuitMessage(0)
End Sub

'WM_PAINTの部分
Sub MainWnd_Paint(hDC As HDC)
BitBlt(hImgDC , 0 , 0,200 ,200 ,hMemDC , 0 , 0, SRCCOPY)
End Sub

'ウインドウが作られた時
Sub MainWnd_Create(ByRef CreateStruct As CREATESTRUCT)
'コントロールは子ウインドウなので、GetDlgItem関数で
'ウインドウハンドルを取得します。
hImgDC = GetDC(GetDlgItem(hMainWnd , ImageBox1))

'メモリDCの初期設定
hMemDC = CreateCompatibleDC(hImgDC)
hBmp = CreateCompatibleBitmap(hImgDC , 200 , 200)
SelectObject(hMemDC , hBmp)

'乱数を初期化
srand(time(NULL))

'エラーのとき終了
If hImgDC = NULL or hMemDC = NULL or hBmp = NULL Then
    MessageBox(hMainWnd , "初期化失敗" , "エラー" , MB_OK)
    ExitProcess(0)
End If     
End Sub

'ボタンクリック
Sub MainWnd_IMAGE_Click()
'ここでメモリDCにお絵かきします。今回は乱数で点を打ちます。
Dim n As Long
Dim x As Long,y As Long
Dim col As Long

For n = 0 To 1000
    x = rand() Mod 200
    y = rand() Mod 200
    col = RGB(rand() Mod 255 , rand() Mod 255 , rand() Mod 255)
    SetPixel(hMemDC , x , y , col)
Next

'実際にWM_PAINTメッセージを送る。
SendMessage(hMainWnd , WM_PAINT , 0 , 0)
End Sub
今回は乱数も使ってみました。
乱数の初期化はsrand関数を使います。
実際に乱数を出すにはrand関数です。
rand Mod xでxまでの数を得ることができます。
Modは余りを求める演算子です。5 Mod 3 で2、10 Mod 6 で4です。
プロジェクトのダウンロードはこちら

実行結果は以下のようになります。ボタンを押すたびに点が増えます。
素敵な星空