2010年5月12日星期三

Windowsグラフィックス諸概念


Last modified on
06.04.03

Windowsグラフィックス諸概念

まず、Windows のグラフィックスをつかう上で絶対に知っておかなければならないことがあります。それは、「デバイスコンテキスト」と「GDI オブジェクト」と「描画メソッド」です。デバイスコンテキスト、GDI オブジェクトと描画メソッドをまとめて、GDI (Graphic Devece Interface) といいます。

ここで話を簡単にするために、スケッチブックに絵を描くことを考えてみましょう。この時点で、スケッチブックの一枚一枚の紙に相当するのが、デバイスコンテキストです。スケッチブックに絵を書いていくように、プログラマはデバイスコンテキストに記述していくことになります。さらに、絵を書くためには、ペンや鉛筆などが必要です。これに相当するものが、 GDI オブジェクトです。GDI オブジェクトで、ペンの色をや、ブラシの色を指定してやることで、デバイスコンテキストに描画ができるようになります。そして実際に描画を行うのが描画メソッドです。この描画メソッドをつかうことによって、ラインや円を書いていくことができるようになります。

以上の3つについてわかっていれば、ここでの説明はもうほとんどありません。あとは実際にどのように描画を行うのか見ていってみましょう。

目次へ


実際に描画

それでは実際に描画を行ってみましょう。普通にウィンドウを作成して、その上にラインと円を描画してみましょう。その前に下準備をしておきます。もう少しプログラムが楽になるように、同じようなプログラムは別ファイルにまとめてしまいましょう。(WinMain関数も含む)

userlib.h

/*******************************************************************************

* ユーザー定義ライブラリヘッダー <>

*

* userlib.c のヘッダーファイル

*

*******************************************************************************/

#ifndef _USERLIB_H_

#define _USERLIB_H_

/********************************************************************************

* 定数の定義 ここに定数を定義していきます

********************************************************************************/

#define APP_NAME "TESTAPP"

#define APP_TITLE "テストアプリケーション"

/********************************************************************************

* 構造体 ここに構造体を定義していきます

********************************************************************************/

/********************************************************************************

* 関数のプロトタイプ

********************************************************************************/

ATOM MyRegisterClass(HINSTANCE hInstance, LPCTSTR lpszMenuName);

BOOL InitInstance(HINSTANCE hInstance, HMENU hMenu);

WPARAM EasyMessageLoop();

/* これは必ず作成すること */

LRESULT CALLBACK WndMainProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);

#endif

/*** end of file ****************************************************************/

userlib.c

/********************************************************************************

* ユーザー定義ライブラリ <>

*

* 自分にとって便利な関数を定義しておきます

********************************************************************************/

#define WIN32_LEAN_AND_MEAN

#include

#include "userlib.h"

/********************************************************************************

* ウィンドウクラスの定義

*

* hInstance : アプリケーションハンドル

* lpszMenuName : メニュー名

*

* 戻り値 : 成功したら固有のアトムを返す; 失敗したら 0

********************************************************************************/

ATOM MyRegisterClass(HINSTANCE hInstance, LPCTSTR lpszMenuName)

{

WNDCLASSEX wcex;

wcex.cbSize = sizeof(wcex);

wcex.style = CS_HREDRAW | CS_VREDRAW;

wcex.lpfnWndProc = WndMainProc;

wcex.cbClsExtra = 0;

wcex.cbWndExtra = 0;

wcex.hInstance = hInstance;

wcex.hIcon = LoadIcon(NULL, IDI_APPLICATION);

wcex.hCursor = LoadCursor(NULL, IDC_ARROW);

wcex.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);

wcex.lpszMenuName = lpszMenuName;

wcex.lpszClassName = APP_NAME;

wcex.hIconSm = NULL;

return RegisterClassEx(&wcex);

}

/********************************************************************************

* ウィンドウの作成

*

* hInstance : アプリケーションハンドル

* hMenu : メニューハンドル

*

* 戻り値 : 成功したら TRUE; 失敗したら FALSE

*

********************************************************************************/

BOOL InitInstance(HINSTANCE hInstance, HMENU hMenu)

{

HWND hWnd = NULL;

if((hWnd = CreateWindowEx(

WS_EX_APPWINDOW,

APP_NAME,

APP_TITLE,

WS_OVERLAPPEDWINDOW,

CW_USEDEFAULT,

CW_USEDEFAULT,

CW_USEDEFAULT,

CW_USEDEFAULT,

NULL,

hMenu,

hInstance,

NULL)) == NULL) return FALSE;

ShowWindow(hWnd, SW_SHOWNORMAL);

UpdateWindow(hWnd);

return TRUE;

}

/********************************************************************************

* 簡易メッセージループ

*

* 戻り値 : WM_QUIT メッセージからの戻り値

********************************************************************************/

WPARAM EasyMessageLoop()

{

MSG msg;

while(GetMessage(&msg, NULL, 0L, 0L))

{

TranslateMessage(&msg);

DispatchMessage(&msg);

}

return msg.wParam;

}

/********************************************************************************

* メイン関数

********************************************************************************/

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,

LPSTR lpCmdLine, int nShowCmd)

{

if(!MyRegisterClass(hInstance, NULL)) return 0;

if(!InitInstance(hInstance, NULL)) return 0;

return EasyMessageLoop();

}

/*** end of file ****************************************************************/

上記2つのファイルを一緒にコンパイルしてください。上の関数は、前回の例題でつかったものとほぼいっしょです。これからは、ここに定義してある関数は、あたりまえのものとしてつかっていきます。自分でも便利な関数を作ったりしたら、ここに追加していって自分独自の便利な関数定義ファイルを作っていきましょう。(注:これらの関数は、プロジェクトに追加しないと使用できませんから、必ずプロジェクトに追加しておいてください)

それでは本題に戻ります。ウィンドウを作成して、その上にラインと円を表示してみます。ウィンドウは、描画されるときに WM_PAINT メッセージを呼び出します。このメッセージは、ウィンドウが再描画されるとき、例えば最小化状態から復帰したり、一部分がほかのウィンドウに隠されているときに、アクティブになる時などに呼び出されます。このメッセージを拾って、ウィンドウに描画してみましょう。

/********************************************************************************

* グラフィックを描いてみよう1

********************************************************************************/

#define WIN32_LEAN_AND_MEAN

#define STRICT

#include

#include "userlib.h"

void OnPaint(HDC hDC);

/********************************************************************************

* コールバック関数

********************************************************************************/

LRESULT CALLBACK WndMainProc(HWND hWnd, UINT Msg,

WPARAM wParam, LPARAM lParam)

{

PAINTSTRUCT ps;

HDC hDC = NULL;

switch(Msg)

{

case WM_DESTROY:

PostQuitMessage(0);

break;

case WM_PAINT:

hDC = BeginPaint(hWnd, &ps);

OnPaint(hDC);

EndPaint(hWnd, &ps);

break;

default:

return DefWindowProc(hWnd, Msg, wParam, lParam);

}

return 0L;

}

/********************************************************************************

* メッセージ処理

********************************************************************************/

void OnPaint(HDC hDC)

{

MoveToEx(hDC, 10, 10, NULL);

LineTo(hDC, 30, 10);

Ellipse(hDC, 0, 0, 30, 20);

}

さて、見て分かるようにデバイスコンテキストの取得には BeginPaint 関数をつかっています。デバイスコンテキストは、ハンドルの形で取得できます。あとはこのハンドルをつかって、線を描いたり、楕円を描いたりするだけです。簡単ですよね。デバイスコンテキストの使用の終了には、EndPaint 関数をつかいます。これで描画の終了です。この2つの関数は、相関関係にあるので、必ずいっしょに用いてください。また、この2つの関数は WM_PAINT メッセージ内でしか使えません。それ以外の場合は、GetDC / ReleaseDC をつかいます。WM_PAINT 以外でグラフィックの処理を行いたい場合は、この2つの関数を用いましょう。PAINTSTRUCT 構造体については、普通のユーザーはつかうことはないので深く考える必要はないですよ。BeginPaint について MSDN ライブラリ内には次のようにかかれています。

ref . An application should not call BeginPaint except in response to a WM_PAINT message. Each call to BeginPaint must have a corresponding call to the EndPaint function. (About BeginPaint) (任意のアプリケーションは、WM_PAINT以外のメッセージ処理においてBeginPaintを呼び出してはいけない。云々…)

実際の描画には、 MoveToEx / LineTo / Ellipse 描画メソッドをつかっています。 MoveToEx 関数は現在の描画ポイント(ラインの引き始めの点)を移します。 LintTo 関数は、現在の描画ポイントから指定の描画ポイントまでラインを引きます。 Ellipse 関数は、楕円(円)を描きます。関数の説明については、MSDN ライブラリを見てくださいね。

こんな感じで、結構簡単にグラフィックを描くことができます。ここではデバイスコンテキストと描画メソッドをつかってみました。つぎは GDI オブジェクトをつかってみましょう。

目次へ


GDIオブジェクト

それでは GDI オブジェクトをつかってみましょう。そのまえに、 GDI オブジェクトについてもう少し詳しく説明しておきましょう。デバイスコンテキストに描画するには、ペンやブラシの属性が決まっていなければなりません。ペンというのは、名前のとおり直線や円を描くときに線を引く属性のことです。使用するペンによって太さが変わったり、直線が破線になったりします。ブラシは塗りつぶしの GDI オブジェクトで、塗りつぶすときの属性が指定されています。ウィンドウズでは、あらかじめデフォルトのペンやブラシが設定されています。自分で変更したいときは、自分で作成して変更することになります。

GDI オブジェクトには、次の7種類あります。

· ビットマップ

· ブラシ

· フォント

· 論理パレット

· パス

· ペン

· リージョン

このなかで、ビットマップ、ブラシ、フォント、ペンを紹介していきます。 GDI オブジェクトは OS の内部で保存されるので、ユーザー自体はハンドルの形で扱うことになります。つまり、GDI オブジェクトを取得するときに、OS からハンドルをもらい、つかう GDI オブジェクトによってハンドルを OS に指定することになります。ほとんど OS 任せなので、簡単でしょう。ユーザーのすることは GDI オブジェクトのハンドル(カギ)をなくさないように管理することです。このカギを無くしてしまうと、作成した GDI オブジェクトにアクセスできないだけではなく、開放もされないので、メモリにずっと残ることになります。いわゆる「オブジェクトリーク」を起こしてしまうので、絶対なくさないようにしましょう。

目次へ


ペンオブジェクトを使ってみる

さて、それでは実際に ペンオブジェクトを作成してみましょう。次のプログラムを見てください。今回は WM_PAINT をつかわずに、WM_LBUTTONDOWN をつかってみましょう。このメッセージを引っ掛けて描画してみます。

/********************************************************************************

* GDIオブジェクトをつかってみよう

********************************************************************************/

#define WIN32_LEAN_AND_MEAN

#define STRICT

#include

#include "userlib.h"

void OnLButtonDown(HWND hWnd, POINT p);

/********************************************************************************

* メッセージプロシージャ

********************************************************************************/

LRESULT CALLBACK WndMainProc(HWND hWnd, UINT Msg,

WPARAM wParam, LPARAM lParam)

{

POINT p;

HDC hDC = NULL;

switch(Msg)

{

case WM_DESTROY:

PostQuitMessage(0);

break;

case WM_LBUTTONDOWN:

p.x = LOWORD(lParam);

p.y = HIWORD(lParam);

OnLButtonDown(hWnd, p);

break;

default:

return DefWindowProc(hWnd, Msg, wParam, lParam);

}

return 0L;

}

/********************************************************************************

* メッセージ処理

********************************************************************************/

void OnLButtonDown(HWND hWnd, POINT p)

{

HDC hDC = NULL;

HPEN hOldPen = NULL, hPen = NULL;

// デバイスコンテキストの取得

hDC = GetDC(hWnd);

// ペンの作成

hPen = CreatePen(PS_DOT, 3, RGB(0, 255, 128));

// ペンの指定

hOldPen = (HPEN)SelectObject(hDC, hPen);

// 円を描く(半径10)

Ellipse(hDC, p.x - 10, p.y - 10, p.x + 10, p.y + 10);

// ペンを元のペンに戻す

SelectObject(hDC, hOldPen);

// 作成したペンオブジェクトを抹消

DeleteObject(hPen);

// デバイスコンテキストの開放

ReleaseDC(hWnd, hDC);

}

このようにペンオブジェクトをつかいます。ここでは、デバイスコンテキストの作成に GetDC ReleaseDC を用いています。

ペンの作成には、 CreatePen 関数をつかいます。作成したペンをデバイスコンテキストに指定するには、 SelectObject 関数をつかいます。ペンをデバイスコンテキストに指定しないと、作成したペンを使えませんので注意してください。さて、 SelectObject は戻り値に直前に指定されていたペンオブジェクトを返します。これはちゃんと保存をしておいてください。作成したペンオブジェクトは開放した時点で無効になってしまいますので、直前のペンオブジェクトを元に戻す必要があるのです。必ずこのプロセスは忘れないでください。さて、ペンオブジェクト(GDI オブジェクト)を開放するには、DeleteObject 関数をつかいます。作成したものは、必ず開放するようにしてください。でないとメモリリークの原因になります。

RGB マクロは COLORREF(32ビット) タイプの色値を返します。

目次へ


ブラシオブジェクトを使ってみる

さて次はブラシオブジェクトをつかってみましょう。ブラシは塗りつぶしにつかいます。早速例題を見てみましょう。

/********************************************************************************

* メッセージ以外は前回の例題と同じなので省略

********************************************************************************/

// メッセージ処理

void OnLButtonDown(HWND hWnd, POINT p)

{

HDC hDC = NULL;

HBRUSH hBrush = NULL, hOldBrush = NULL;

HPEN hPen = NULL, hOldPen = NULL;

POINT cp[3];

cp[0].x = p.x - 30 - 20;

cp[0].y = p.y - 30 + 20;

cp[1].x = p.x - 30 + 20;

cp[1].y = p.y - 30 + 20;

cp[2].x = p.x - 30;

cp[2].y = p.y - 30 - 20;

hDC = GetDC(hWnd);

hPen = CreatePen(PS_SOLID, 1, RGB(200, 255, 200));

hOldPen = (HPEN)SelectObject(hDC, hPen);

hBrush = CreateSolidBrush(RGB(0, 255, 200));

hOldBrush = (HBRUSH)SelectObject(hDC, hBrush);

Polygon(hDC, cp, 3);

hBrush = CreateHatchBrush(HS_DIAGCROSS, RGB(255, 0, 0));

DeleteObject( SelectObject(hDC, hBrush) );

Ellipse(hDC, p.x + 30, p.y + 30, p.x + 60, p.y + 60);

SelectObject(hDC, hOldBrush);

SelectObject(hDC, hOldPen);

DeleteObject(hBrush);

DeleteObject(hPen);

ReleaseDC(hWnd, hDC);

}

ブラシの作成には、 CreateSolidBrush CreateHatchBrush 関数をつかっています。実行してみたら分かるように、 CreateSolidBrush で作成したブラシは塗りつぶしを行います。 CreateHatchBrush で作成したブラシは斜線(ハッチ)の入った塗りつぶしになります。ハッチパターにはこの他いろいろありますので、自分で確認しておいてください。また、ここでは多角形を描くのに Polygon 関数をつかっています。今回は三角形を描きましたが、頂点数を増やせば、5角形でも6角形でも描けます。

このような感じになります。

目次へ


フォントオブジェクトを使ってみる

それでは次はフォントを扱ってみましょう。ウィンドウズには標準で付属している「MS ゴシック」をつかってみます。

/********************************************************************************

* メッセージ処理以外は前回例題と同じ

********************************************************************************/

#include

// メッセージ処理

void OnLButtonDown(HWND hWnd, POINT p)

{

HFONT hFont = NULL, hOldFont = NULL;

HDC hDC = NULL;

char lpStr[80];

int red, green, blue;

red = rand() % 256;

green = rand() % 256;

blue = rand() % 256;

hDC = GetDC(hWnd);

hFont = CreateFont(24, 0, 450, 450, FW_NORMAL, FALSE, FALSE, FALSE, SHIFTJIS_CHARSET,

OUT_CHARACTER_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY,

DEFAULT_PITCH, "MS ゴシック");

hOldFont = (HFONT)SelectObject(hDC, hFont);

SetTextColor(hDC, RGB(red, green, blue));

lstrcpy(lpStr, "テストです");

SetBkMode(hDC, TRANSPARENT);

TextOut(hDC, p.x, p.y, lpStr, lstrlen(lpStr));

SelectObject(hDC, hOldFont);

DeleteObject(hFont);

ReleaseDC(hWnd, hDC);

}

フォントオブジェクトの作成には CreateFont 関数をつかいます。パラメータの数なんと13!で、やたら多いのですが MSDN ライブラリを見れば、多いだけで大して問題はないことに気づくでしょう。もしかしたらCreateFontIndirect 関数で、構造体をつかったほうがいいかもしれません。フォントの色の指定には SetTextColor 関数をつかいます。背景モードの指定には SetBkMode 関数をつかいます。この関数をつかうことで、テキストの背景を透明にしたり、色をつけたりすることが出来ます。テキストの出力には TextOut 関数をつかいます。そのほかテキストを出力する関数には DrawText / DrawTextEx 関数をつかいます。

このような感じになります。

(注1) ウィンドウズプログラミングでは、文字列操作関数は strlen strcpy をつかう代りに lstrlen lstrcpy をつかいます。これは、sprintf をつかわず wsprintf をつかう理由と同じです。 lstrlen / lstrcpy / wsprintf はウィンドウズのライブラリに定義されています。ここでもし標準関数をつかってしまうと、実行プログラムに標準関数のライブラリをつむことになるので、実行ファイルがやや大きくなってしまいます。できるだけ lstrlen wsprintf をつかうようにしましょう。

2002年追記  と思いきや、VC++の場合は、既に標準ライブラリを積んでいるようです。というのも、VC++のライブラリは初期化の時点で標準ライブラリの初期化も行っているからです。

(注2)フォント名で「MS ゴシック」となっていますが、「MS」と「ゴシック」は全角文字、その間の空白は半角なので気をつけてください。

目次へ


ビットマップを使ってみる

次はビットマップを扱ってみましょう。結構簡単に扱えます。そのまえに、何でもいいですからビットマップ形式のファイルを作っておいてください。めんどくさい方は、ここから取っていってください。

画像を落としたら、きちんとビットマップに変換して、プロジェクトのフォルダの中に加えてください。

/********************************************************************************

* メッセージ処理ビットマップの使用

* メッセージ処理以外は前回例題と同じ

********************************************************************************/

#define BMP_FILE_NAME "neko.bmp"

// メッセージ処理

void OnLButtonDown(HWND hWnd, POINT p)

{

HDC hDC = NULL, hDCBitmap = NULL;

HBITMAP hBitmap = NULL;

hDC = GetDC(hWnd);

hDCBitmap = CreateCompatibleDC(hDC);

hBitmap = (HBITMAP)LoadImage(NULL, BMP_FILE_NAME, IMAGE_BITMAP,

179, 109, LR_LOADFROMFILE|LR_CREATEDIBSECTION);

SelectObject(hDCBitmap, hBitmap);

BitBlt(hDC, p.x, p.y, 179, 109, hDCBitmap, 0, 0, SRCCOPY);

DeleteDC(hDCBitmap);

DeleteObject(hBitmap);

ReleaseDC(hWnd, hDC);

}

ビットマップオブジェクトの作成には、 LoadImage 関数をつかいます。実際コピーをする場合には、ビットマップのメモリデバイスコンテキストを割り当ててやる必要があります。そのため、メモリデバイスコンテキストをCreateCompatibleDC で作成し、このデバイスコンテキストにビットマップオブジェクトを割り当てています。メモリ転送には BitBlt 関数をつかっています。CreateCompatibleDC 関数でデバイスコンテキストを作成した場合、このデバイスコンテキストを開放するには、 ReleaseDC 関数ではなく DeleteDC 関数をつかいます。

このような感じになります。

デバイスコンテキストの中にもいくつかの種類があって、メモリデバイスコンテキストもいくつかあるデバイスコンテキストのひとつです。メモリデバイスコンテキストは、ビットマップに書き込みを行うことが出来るデバイスコンテキストのことです。ちなみに今までわたし達が画面の描画につかってきたデバイスコンテキストを、ディスプレイデバイスコンテキストといいます。そのほかには、プリンタデバイスコンテキストなどがあります。

ここの冒頭でもいったように、デバイスコンテキストは絵を描くことにたとえたらスケッチブックみたいなものです。そのスケッチブックが、プリンタから出力されたり、ディスプレイに描画されたり、ビットマップが描かれていたりするわけです。

目次へ


描画メソッド

描画メソッドについては、あまり説明しないまま今までつかってきました。 LineTo 関数や Ellipse 関数などです。少数のメソッドしか登場していないので、ここでほかの描画メソッドについても紹介しておきましょう。

描画メソッドには、塗りつぶし描画メソッド曲線描画メソッドがあります。塗りつぶし描画メソッドは、文字のとおり塗りつぶしを行います。曲線描画メソッドは、塗りつぶしを行わずに、曲線のみを描画します。塗りつぶしはブラシで設定します。デバイスコンテキストで設定してあるブラシで塗りつぶしを行います。

塗りつぶし描画メソッド

メソッド名

説明

Chord

弓形を描画します。

Ellipse

楕円(円)を描画します。

FillRect

長方形を描画します。

FrameRect

長方形の境界線を指定されたブラシで描画します。

InvertRect

指定された長方形の内部を反転します。

Pie

扇形を描画します。

Polygon

多角形を描画します。

PolyPolygon

連続した多角形を描画します。

Rectangle

長方形を描画します。 FillRect と違って枠をペンで内部をブラシで描画します。

RoundRect

角の丸い長方形を描画します。

曲線描画メソッド

メソッド名

説明

AngleArc

中心から円弧の開始ポイントまで直線を描き、円弧を描画します。

Arc

楕円弧を描画します。カレントポイントを使用しません。

ArcTo

楕円弧を描画します。カレントポイントを使用します。

GetArcDirection

円弧の描画方向を取得します。

LineTo

カレントポイントから指定されたポイントまで直線を描画します。

MoveToEx

カレントポイントを指定されたポイントまで移動します。

PolyBezier

ひとつ以上のベジェ曲線を描画します。カレントポイントを使用しません。

PolyBezierTo

ひとつ以上のベジェ曲線を描画します。カレントポイントを使用します。

PolyDraw

直線とベジェ曲線をまとめて描画します。

PolyLine

連続した線分を描画します。カレントポイントを使用しません。

PolyLineTo

連続した線分を描画します。カレントポイントを使用します。

PolyPolyLine

複数の連続した線分を描画します。

SetArcDirection

円弧の描画方向を設定します。

用語

解説

(注1)カレントポイント

OS内部で保存している描画開始ポイント。

(注2)円弧の描画方向

時計回りか半時計回りか。

この他に、関数は山のように出てきますが、ここでは割愛させていただきます。だいたい「あったらいいな」と思うような機能の関数はそろってますので、じぶんで MSDN をあさって探してみてください。

Windows GDI 関数以外に、いくつか描画を扱うライブラリがあります。 GDIではハードウェアの性能をフル活用するような高速に表示を行うようなものには向きません。こういう場合は、 DirectX OpenGL などを使います。DirectX は主にゲームの描画処理に使われ、OpenGL は主に CAD 関係に使われます。どちらのライブラリも 3D 処理をすることができます。

DrawText 与 DraqTextEx的区别

在第2个函数第二个参数的地方 Drawtext 是 LPCTSTR 而 DrawtextEx是 LPTSTR在使用 CString的时候 需要转换Drawtext 可以直接引用CString型变量 而DrawtextEx 需要做一个转换DrawTextEx(hdc, (LPTSTR)(LPCTSTR)szTextJP, -1, &myRect, MY_TEXT_FORMAT, &dtp);


参考引文:CString LPCTSTR LPTSTR 类型的相互转化
  // 変数定義
  LPTSTR s_t;
  LPCTSTR s_ct;
  CString str;
  CString sResult;
  
  const i_ct = 5;
  int i = 10;
  const int *p_ct = &i_ct;
  int *p = &i;
  //メンッド1.CString -> LPTSTR
  //初期化する
  s_t="NULL";
  s_ct="NULL";
  str="SecBug";
  
  //変換する
  s_t = (LPTSTR)(LPCTSTR)str;
  //結果お表示する
  sResult = CString("変換 CString から LPTSTRまで, OK : ") + s_t;
  MessageBox(sResult);
  //メンッド2.CString -> LPCTSTR
  //初期化する
  s_t="NULL";
  s_ct="NULL";
  str="SecBug";
  
  //変換する
  s_ct = str;
  //結果を表示する
  sResult = CString("変換 CString から LPCTSTRまで, OK : ") +s_ct;
  MessageBox(sResult);
  //メンッド3.LPCTSTR -> LPTSTR
  //初期化する
  s_t="NULL";
  s_ct="NULL";
  str="SecBug";
  
  //変換する
  s_ct = str;
  // s_t = s_ct; //error , the same with p = p_ct;
  //結果を表示する
  sResult = CString("変換 LPCTSTR から LPTSTRまで, NG ") ;
  MessageBox(sResult);
  //メンッド4.LPTSTR -> LPCTSTR
  //初期化する
  s_t="Sec";
  s_ct="Bug";
  str="SecBug";
  
  //変換する
  s_ct = s_t ;//wright, the same with p_ct=p;
  //結果を表示する
  sResult = CString("変換 LPTSTR から LPCTSTRまで, OK ") + s_ct;
  MessageBox(sResult);

DrawText

DrawText

目录[隐藏]

函数功能
函数原型
参数
返回值
备注
速查
在K线图中的运用:


函数功能

  该函数在指定的矩形里写入格式化的正文,根据指定的方法对正文格式化(扩展的制表符,字符对齐、折行等)。
  要指定额外的格式化选项,请使用DrawTextEx函数。
  

函数原型

  int DrawText(
  HDC hDC, // 设备描述表句柄
  LPCTSTR lpString, // 将要绘制的字符串
  int nCount, // 字符串的长度
  LPRECT lpRect, // 指向矩形结构RECT的指针
  UINT uFormat // 正文的绘制选项
  );

参数

  hdc:
  [输入]设备环境句柄。
  lpString:
  [输入]指向将被写入的字符串的指针,如果参数nCount是-1,则字符串必须是以\0结束的。 如果uFormat包含DT_MODIFYSTRING,则函数可为此字符串增加4个字符,存放字符串的缓冲区必须足够大,能容纳附加的字符。
  nCount:
  [输入]指向字符串中的字符数。如果nCount为-1,则lpString指向的字符串被认为是以\0结束的,DrawText会自动计算字符数。
  lpRect:
  [输入/输出]指向结构RECT的指针,其中包含文本将被置于其中的矩形的信息(按逻辑坐标)。
  uFormat:
  [输入]指定格式化文本的方法。它可以下列值的任意组合,各值描述如下:
  
说明
DT_BOTTOM将正文调整到矩形底部。此值必须和DT_SINGLELINE组合。
DT_CALCRECT决定矩形的宽和高。
  如果正文有多行,DrawText使用lpRect定义的矩形的宽度,并扩展矩形的底部以容纳正文的最后一行。
  如果正文只有一行,则DrawText改变矩形的右边界,以容纳下正文行的最后一个字符。
  出现上述任何一种情况,DrawText返回格式化正文的高度,而不是绘制正文。
DT_CENTER使正文在矩形中水平居中。
DT_VCENTER使正文在矩形中垂直居中。
  (DreamSmart注:此参数必须和DT_SINGLE连用,否则GDI无法计算目的矩形)
DT_EDITCONTROL复制多行编辑控制的正文显示特性。
  特殊地,为编辑控制的平均字符宽度是以同样的方法计算的,此函数不显示只是部分可见的最后一行。
DT_END_ELLIPSIS对于显示的文本,如果结束的字符串的范围不在矩形内,它会被截断并被附加到椭圆中。
  如果一个字母不是在字符串的末尾处超出了矩形范围,它不会被椭圆截断。
  字符串不会被修改,除非指定了DT_MODIFYSTRING标志。
DT_EXPANDTABS扩展制表符,每个制表符的缺省字符数是8。
  DT_WORD_ELLIPSIS, DT_PATH_ELLIPSIS和DT_END_ELLIPSIS不能和此参数一起使用
DT_EXTERNALLEADING在行的高度里包含字体的外部标头,通常,外部标头不被包含在正文行的高度里。
DT_HIDEPREFIX忽略正文中的前缀字符(&),并且前缀字符后面的字母不会出现下划线。其它前缀字符的调用方式不受影响。
  输入的字符串: "A&bc&&d"
  正常: "Abc&d"
  DT_HIDEPREFIX: "Abc&d"
DT_INTERNAL用系统字体来计算正文度量。
DT_LEFT正文左对齐。
DT_MODIFYSTRING修改给定的字符串来匹配显示的正文。
  此标志必须和DT_END_ELLIPSIS 或 DT_PATH_ELLIPSIS同时使用。
DT_NOCLIP无裁剪绘制。当DT_NOCLIP使用时DrawText的使用会有所加快。
DT_NOFULLWIDTHCHARBREAK在宽字符的字符串中防止行断开,因此折行规则相当于单字符的字符串。
  例如,我们可以用在棒子版的windows中,为图标标签提供更好的可读性。
  除非指定DT_WORDBREAK,否则此值没有作用。
DT_NOPREFIX关闭前缀字符的处理。
  通常DrawText解释助记前缀字符,&为给其后的字符加下划线,解释&&为显示单个&。指定DT_NOPREFIX,这种处理被关闭。
DT_PATH_ELLIPSIS对于显示的正文,替换字符串在椭圆中的字符,以确保结果能在合适的矩形内。
  如果该字符串包含反斜杠(\)字符,DT_PATH_ELLIPSIS尽可能的保留最后一个反斜杠之后的正文。
  字符串不会被修改,除非指定了DT_MODIFYSTRING标志。
DT_PREFIXONLY仅仅在(&)前缀字符的位置下绘制一个下划线。不绘制字符串中的任何其他字符。
  输入的字符串: "A&bc&&d"
  正常: "Abc&d"
  DT_PREFIXONLY:" _ "
DT_RIGHT正文右对齐。
DT_RTLREADING当选择进设备环境的字体是希伯来文或阿拉伯文字体时,为双向正文安排从右到左的阅读顺序都是从左到右的。
DT_SINGLELINE显示正文的同一行,回车和换行符都不能折行。
DT_TABSTOP设置制表,参数uFormat的15"C8位(低位字中的高位字节)指定每个制表符的字符数,每个制表符的缺省字符数是8。
  注意:DT_CALCRECT, DT_EXTERNALLEADING, DT_INTERNAL,
  DT_NOCLIP, DT_NOPREFIX值不能和DT_TABSTOP值一起使用。
DT_TOP正文顶端对齐(仅对单行)。
DT_WORDBREAK断开字。当一行中的字符将会延伸到由lpRect指定的矩形的边框时,此行自动地在字之间断开。一个回车一换行也能使行折断。
DT_WORD_ELLIPSIS截短不符合矩形的正文,并增加椭圆。

返回值

  如果函数调用成功,返回值是正文的高度(逻辑单位)。如果指定了DT_VCENTER或DT_BOTTOM,返回值是lpRect->top到绘制的正文的底部的偏移值。
  如果函数调用失败,返回值是0
  Windows NT:若想获得更多错误信息,请调用GetLastError函数。

备注

  函数DrawText用设备环境中的字体选择、正文颜色和背景颜色来写正文。DrawText裁剪正文,不会出现在指定矩形的外面,除非指定了DT_NOCLIP。除非使用DT_SINGLELINE格式化,否则其余的格式都认为正文有多行。
  如果选择的字体对指定的矩形而言太大,DrawText不会试图去换成一种小字体。
  DrawText支持纵和方向均为0的字体。
  设备环境的正文对齐方式必须包括TA_LEFT, TA_TOP和TA_NOUPDATECP标志。
  Windows CE:如果为参数uFormat指定DT_CALCRECT值,必须为lpRect指向的RECT结构设置right和bottom成员。Windows CE不支持uFormat为DT_EXTERNALLEADING。

速查

  Windows NT:3.1及以上版本;Windows:95及以上版本;Windows CE:1.0及以上版本;头文件:wingdi.h;库文件:gdi32.lib;Unicode:在Windows NT环境下以Unicode和ANSI两种方式实现。

在K线图中的运用:

  格式:drawtext(条件表达式子,位置,‘文字’);
  含义:当条件满足时,在指定的位置显示需提示的汉字;
  编写时注意事项:位置要与价格相适应,如果价格在5000,那么位置处用50是显示不出文字的;
  文字前后的标点是英文状态下输入的,不能用中文状态输入。

ReleaseDC

函数功能:函数释放设备上下文环境(DC)供其他应用程序使用。函数的效果与设备上下文环境类型有关。它只释放公用的和设备上下文环境,对于类或私有的则无数。

函数原型:int ReleaseDC(HWND hWnd, HDC hdc);

参数:

hWnd:指向要释放的设备上下文环境所在的窗口的句柄。

hDC:指向要释放的设备上下文环境的句柄

返回值:返回值说明了设备上下文环境是否释放;如果释放成功,则返回值为1;如果没有释放成功,则返回值为0。

注释:每次调用GetWindowDC和GetDC函数检索公用设备上下文环境之后,应用程序必须调用ReleaseDC函数来释放设备上下文环境。

应用程序不能调用ReleaseDC函数来释放由CreateDC函数创建的设备上下文环境,只能使用DeleteDC函数。

速查:Windows NT:3.1及以上版本;Windows:95及以上版本;Windows CE:1.0及以上版本;头文件:winuser.h;库文件:user32.lib。