|
デバイスコンテキストの基本
この章からはMFCでのGDIを使った描画処理について解説していきます。四角形や円を描画したり、文字列を描画したり、ビットマップを描画したりするには、CDCというクラスを使います。DCというのはデバイスコンテキストという意味です。コンテキストというと何か難しい概念のような感じもしますが、まあ、描画に関する処理をひとまとめにしたクラスだと思っていいでしょう。使うのは簡単です。
では、実際に使ってみましょう。いつものようにダイアログベースでプロジェクトを作成します。プロジェクトを作成すると、自動的に必要なコードが作成されますが、その中で次のようなコードができているのがわかると思います。
void CDCDlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // 描画のデバイス コンテキスト
SendMessage(WM_ICONERASEBKGND,
reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);
// クライアントの四角形領域内の中央
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;
// アイコンの描画
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialog::OnPaint();
}
}
|
ダイアログクラスのOnPaint()関数です。OnPaint()関数は、ダイアログが描画されようとしているときに毎回呼び出されます。ここではダイアログがアイコン化されたときのアイコンの描画処理が入っています。しかし、この処理は通常使われないようなので、説明の都合上消してしまいます。代わりに次のように変更してみましょう。
void CDCDlg::OnPaint()
{
CClientDC cdc(this);
cdc.FillSolidRect(10, 10, 20, 20, RGB(255, 0, 0));
CDialog::OnPaint();
}
|
ビルドして実行してみると、次のようにダイアログ上に赤い四角形が描画されているのがわかります。

CDC::FillSolidRect()関数は、指定した領域を指定した色で塗りつぶします。基本的な使い方はこの程度で、非常に簡単です。
では、少々解説していきましょう。CClientDCはCDCの派生クラスです。コンストラクタでthisポインタを渡しているのがわかると思いますが、これは指定したウィンドウ(この場合はダイアログ)のクライアント領域を描画するためのクラスです。クライアント領域というのは、ウィンドウのタイトルバーや、ウィンドウの周りの枠を除いた、ウィンドウの内側の領域です。普通はこの領域に描画するので、CClientDCクラスを使うことになります。
では次にCDC::FillSolidRect()関数を見てみましょう。
| void CDC::FillSolidRect(int x, int y, int cx, int cy, COLORREF clr); |
| 説明: |
指定した領域を指定した色で塗りつぶす |
| 引数: |
x:x座標
y:y座標
cx:幅
cy:高さ
clr:塗りつぶす色 |
| 戻り値: |
なし |
色の指定はCOLORREF型を使います。これは32ビットの値で、赤、青、緑の成分が8ビットずつ使われます。直にCOLORREF型を指定するのは若干わかりにくいので、RGBというマクロが用意されています。これはRGB(r, g, b)という形式で指定します。r、g、bはそれぞれ赤、青、緑の成分で、0〜255の値をとります。
座標の指定ですが、ここではx:10、y:10、cx:20、cy:20と指定したので、四角形の左上の座標が(10, 10)、右下の座標が(30, 30)になります。ここで指定した座標は「クライアント座標」です。クライアント座標というのは、ウィンドウのクライアント領域の左上を原点(0, 0)とした座標系です。これに対して「スクリーン座標」というのは、デスクトップの左上を原点(0, 0)とした座標系です。
では、今度は少し違った方法で描画してみましょう。今度は次のようにコードを変えてみます。
void CDCDlg::OnPaint()
{
CClientDC cdc(this);
CRect rect(10, 10, 30, 30);
CBrush *pOldBrush = NULL, *pBrush = NULL;
int err = 0;
// ストックブラシを選択
if (!err) if ((pOldBrush = static_cast<CBrush *>
(cdc.SelectStockObject(DKGRAY_BRUSH))) == NULL) err = 1;
// 現在のブラシを取得
if (!err) if ((pBrush = cdc.GetCurrentBrush()) == NULL) err = 1;
// 四角形の描画
if (!err) cdc.FillRect(&rect, pBrush);
CDialog::OnPaint();
}
|
ビルドして実行してみると、次のように黒い四角形が描画されているのがわかります。

CDC::FillRect()関数は、指定した領域を、指定したブラシで塗りつぶします。ここでブラシというものが出てきましたが、ブラシというのはGDIオブジェクトの一つです。GDIオブジェクトにはペン(CPen)、ブラシ(CBrush)、フォント(CFont)、ビットマップ(CBitmap)、パレット(CPalette)、領域(CRgn)があり、CDCクラスのオブジェクトはこれらのGDIオブジェクトを一つずつ「選択」しています。描画関数で、特にペンやブラシ、色などを指定しないものは、現在選択されているペンやブラシで描画します。GDIオブジェクトはすべてCGdiObjectクラスの派生クラスです。
独自のブラシを作って使いたい場合は、CBrushクラスのオブジェクトを作って、CDC::SelectObject()関数でそのブラシを選択します。しかしながら、いくつかのGDIオブジェクトはあらかじめシステムで用意されているので、これを使うこともできます。これらは「ストックオブジェクト」と言います。
ストックオブジェクトを選択する場合は、CDC::SelectStockObject()関数を使います。
| virtual CGdiObject* CDC::SelectStockObject(int nIndex); |
| 説明: |
ストックオブジェクトを選択する |
| 引数: |
nIndex:選択するストックオブジェクト |
| 戻り値: |
正常終了した場合、直前に選択されていたGDIオブジェクトへのポインタ。それ以外の場合NULL |
現在選択されているブラシを取得するには、CDC::GetCurrentBrush()関数を使います。
| CBrush* CDC::GetCurrentBrush() const; |
| 説明: |
現在選択されているブラシを取得する |
| 引数: |
なし |
| 戻り値: |
正常終了した場合、ブラシへのポインタ。それ以外の場合NULL |
一度ストックオブジェクトを選択してから、現在のブラシを取得しているので、結局ストックオブジェクトのブラシを取得していることになります。(APIのGetStockObject()関数を使うと直接ストックオブジェクトを取得できますが、ここではMFCのみを使って実装してみました。)
これがCDCクラスの基本的な使い方です。ペンやブラシをいろいろ取り替えながら描画関数で描画するという流れですね。
|