第8章 デバイスコンテキスト


前回は、OnPaintハンドラの中で使用するCPaintDCクラスの解説を しました。それ以外のところで描画するにはどうしたらよいのでしょうか。 SDKではGetDC関数を使いました。MFCでも

CWnd::GetDC CDC* GetDC( );

というのがあります。描画が終わったら

CWnd::ReleaseDC int ReleaseDC( CDC* pDC );

でデバイスコンテキストを解放しなくてはいけません。

また、CClientDCクラスを使うという手もあります。

CClientDC dc(CWnd *pWnd);

という感じで使います。これは、dcを解放する必要はありません。 また、pWndをNULLにするとスクリーン全体のデバイスコンテキストになります。

さて、前章でやったようにデバイスコンテキストの属性を 変化させたとき(ペンを変えたときなど)は、習慣的にもとの属性に戻していました。 では、これをしないとどうなるのでしょうか?

たとえばOnPaintのなかで

1.直線を描画する(デフォルトの黒い直線になる)
2.赤いペンに変える
3.別な直線を描画する(当然赤い直線になる)

というようなプログラムを書きます。ペンを元に戻さずに終了します。 もし、次にOnPaintが呼ばれたとき(ウィンドウが他のウィンドウに隠されて 再度顔を出したときなど)どうなるのでしょうか。1.の直線は 以前選択されていた赤いペンで描画されるのでしょうか。

実はそんなことは起こりません。OnPaintが呼ばれる度にデフォルトの 属性にもどっているからです。

左のプログラムは、クライアント領域を左クリックすると クリックした点を中心に黒丸が、右クリックすると赤丸が描画されます。 また、メニューの「テスト」を選択すると...


左の図のようにスクリーン全体が碁盤状態になってしまいます。 (実際はこのようなプログラムを作ってはいけません)
では、プログラムを見てみましょう。

///////////////////////////////////////////////////////////////////////////// // // Menu // MYMENU MENU DISCARDABLE BEGIN POPUP "ファイル(&F)" BEGIN MENUITEM "終了(&X)", IDM_END END MENUITEM "テスト(&T)", IDM_TEST END

別にどうということもないメニューリソースです。

// grph02.h class CMyApp : public CWinApp { public: virtual BOOL InitInstance(); }; class CMyWindow : public CFrameWnd { public: CMyWindow(); protected: afx_msg void OnPaint(); afx_msg void OnEnd(); afx_msg void OnTest(); afx_msg void OnLButtonDown(UINT, CPoint); afx_msg void OnRButtonDown(UINT, CPoint); DECLARE_MESSAGE_MAP() };

CMyWindowクラスのメンバ関数には、今回処理する メッセージのハンドラ関数を記載しておきます。

// grph02.cpp #include <afxwin.h> #include "grph02.h" #include "resource.h" CMyApp MyApp; BOOL CMyApp::InitInstance() { m_pMainWnd = new CMyWindow; m_pMainWnd->ShowWindow(m_nCmdShow); m_pMainWnd->UpdateWindow(); return TRUE; } BEGIN_MESSAGE_MAP(CMyWindow, CFrameWnd) ON_WM_PAINT() ON_COMMAND(IDM_END, OnEnd) ON_COMMAND(IDM_TEST, OnTest) ON_WM_LBUTTONDOWN() ON_WM_RBUTTONDOWN() END_MESSAGE_MAP() CMyWindow::CMyWindow() { Create(NULL, "猫でもわかるグラフィックス", WS_OVERLAPPEDWINDOW, rectDefault, NULL, "MYMENU"); }

ここまでは、特に説明は必要ないですね。

void CMyWindow::OnPaint() { CPaintDC dc(this); dc.TextOut(10, 10, "猫でもわかる"); dc.SetTextColor(RGB(255, 0, 0)); dc.TextOut(10, 40, "赤色表示"); }

テキストの色もデバイスコンテキスト属性の一つです。 「猫でもわかる」はデフォルトの黒で描画されます。 「赤色表示」は赤で描画されます。これでやめています。 (テキストの色をデフォルトに戻していない)しかし、 再描画が起こっても「猫でもわかる」は黒で描画されます。 (こういうことは経験的にわかっている人が多いはずです)

void CMyWindow::OnEnd() { SendMessage(WM_CLOSE); }

メニューから「終了」を選択したときの処理です。

void CMyWindow::OnTest() { RECT rc; CWnd *pdesktop; CClientDC dc(NULL); int i; pdesktop = GetDesktopWindow(); ::GetClientRect(pdesktop->m_hWnd, &rc); for (i = 0; i <= rc.right; i += 20) { dc.MoveTo(i, 0); dc.LineTo(i, rc.bottom); } for (i = 0; i <= rc.bottom; i += 20) { dc.MoveTo(0, i); dc.LineTo(rc.right, i); } }

CClientDC dc(NULL);でスクリーンのデバイスコンテキストを取得しています。 このプログラムのように、自分のウィンドウをはみ出して描画するような プログラムを書いてはいけません。(他人に迷惑をかける)

GetDesktopWindowはSDKにも同じ名前の関数がありました。 MFCでは

CWnd::GetDesktopWindow static CWnd* PASCAL GetDesktopWindow( );

となっています。戻り値はデスクトップを識別するCWnd のポインタです。さて、デスクトップのクライアント領域の 大きさを取得するためここでは、API関数(SDK)のGetClientRect()を 使っています。そのためにはデスクトップのウィンドウハンドルが必要です。 どのようにすればよいのでしょうか?

CWndオブジェクトのポインタ(pCWnd)があれば

HWND hWnd = pCWnd->m_hWnd;

で取得できます。これを知っているだけでSDKの人はずいぶん気が楽になります。 MFCがわからなくなったらSDKの手法を使えますからね。

void CMyWindow::OnLButtonDown(UINT nFlg, CPoint pt) { CDC *pdc; pdc = GetDC(); pdc->Ellipse(pt.x-10, pt.y-10, pt.x+10, pt.y+10); ReleaseDC(pdc); }

左ボタンが押されたときの処理です。GetDCはMFCではCDCオブジェクトへの ポインタが取得されるという点に注意してください。

CDC::Ellipse BOOL Ellipse( int x1, int y1, int x2, int y2 ); BOOL Ellipse( LPCRECT lpRect );

楕円を描画します。この楕円に外接する四角形の左上、右下の座標が 引数となります。または、外接する四角形を表すRECT構造体へのポインタを 指定します。

また、クリックされた座標はOnLButtonDown()の第2引数でわかります。 ちなみに第1引数はコントロールキーとかシフトキーが押されているかを 調べるのに使います。

void CMyWindow::OnRButtonDown(UINT nFlg, CPoint pt) { CClientDC dc(this); CPen pen, *pOldPen; pen.CreatePen(PS_SOLID, 1, RGB(255, 0, 0)); pOldPen = dc.SelectObject(&pen); dc.Ellipse(pt.x-10, pt.y-10, pt.x+10, pt.y+10); dc.SelectObject(pOldPen); }

右ボタンが押されたときの処理です。 左の時とほぼ同じことをしていますが、dcの取得の仕方が違います。 また、ペンを赤くしています。

線の描画とか、ペンについてはまだ細かい注意点がいろいろあります。


[MFC Index] [総合Index] [Previous Chapter] [Next Chapter]

Update 01/Apr/1998 By Y.Kumei
当ホーム・ページの一部または全部を無断で複写、複製、 転載あるいはコンピュータ等のファイルに保存することを禁じます。