タイトル

Window

タイトル

1,座標 3種類の座標 座標2 原点 範囲
2,起動時の設定 サイズ 色

1,座標

3種類の座標

Windowの座標には3種類あります。

スクリーン座標とは、画面の左上を原点としたものです。
クライアント座標は下図のqに相当する部分を原点にしたものです。
いままでにTextOutなどで指定していた座標は実はクライアント座標だったのです。

座標

ここに3種類のCRect型の変数を宣言してみました。


CRect p,q,r;

GetParent()->GetWindowRecr(&p);
GetWindowRect(&q);
GetClientRect(&r);

pとqはスクリーン座標で、rはクライアント座標を用いています。
pは図のpからWindowの右下までの矩形座標を返します。
qは図のqからWindowの右下までの矩形座標を返します。
rは原点からWindowの内側の右下までの矩形座標を返します。

p,qの各4成分は、o点を原点としているので、それぞれ値が変わってきます。
しかし、rはq点が原点なのでr.topとr.leftは両方とも0になります。


座標2

もう一度、座標について復習します。
VisualC++で使用する座標には以下の3つあります。

●物理座標

スクリーンの左隅を(0,0)として、
画面の1画素が1ピクセルに対応する座標。
別名「デバイス座標」とも呼ばれる。

●クライアント座標

Window内の座標で、クライアント領域の左隅が(0,0)になります。

●論理座標

実際には画面に表示されないない仮想の座標です。
範囲は(-32767,-32767)〜(32767,32767)の範囲があります。

これらの数値はすべて整数になります。
座標に関連した関数が扱う座標系は以下の通りです。

物理座標 GetWindowRect
クライアント座標 GetClientRect , SetViewportExt,Org
OnLButtonDownの引数のpoint
論理座標 MoveTo , LineTo , SetPixel SetWindowExt,Org

これらの関係は、以下のようになっています。

座標の関係

LineToなどの描画は論理座標に対して行います。
そのうち、特定の部分をビューポートが抜き出して
クライアント領域に張り付けます。

デフォルトでは、ビューポートはクライアント領域全体に
張り付いていて倍率も同じで、原点は左上にあります。
つまり、クライアントの座標とビューポートの座標は一致しています。
また、ビューポートは論理座標からWindowと同じ大きさの領域を抜き出してきます。


原点

では、原点を中心に持ってくる場合を考えます。


void CTestView::OnDraw(CDC* pDC)
{
	CTestDoc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);

	CRect r;
	GetClientRect(r);
	pDC->SetViewportOrg(r.right/2,r.bottom/2);

	double x,y;
	for (x=-100.0; x<100.0; x++){
		pDC->MoveTo((int)(x*10),-1000);pDC->LineTo((int)(x*10),1000);
		pDC->MoveTo(-1000,(int)(x*10));pDC->LineTo(1000,(int)(x*10));
		y=x*x/100;
		pDC->SetPixel((int)x,(int)y,0);
	}
}

SetViewportOrg という関数はビューポートの原点をクライアント座標に対して
どこに持ってくるかというものです。
ここでは、Windowの中心に持ってくるようにしているので
2次関数の頂点は、Windowの大きさを変えても常に中心にあります。

原点の関係

先ほどの関係図でいうと、論理座標の方のWindowはデフォルトのままです。
ビューポートの原点が図の左のように中央になりました。
しかし、ビューポートは無限に広い平面と考えられるので
画面がとぎれるということがありません。
従って、2次関数はウィンドウの範囲内では、欠けることがありません。


範囲

次に、論理座標の(0,0)から(200,200)の部分を 画面全体に表示する場合を考えます。


void CTestView::OnDraw(CDC* pDC)
{
	CTestDoc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);

	CRect r;
	GetClientRect(r);
	pDC->SetMapMode(MM_ANISOTROPIC);
	pDC->SetWindowExt(200,200);
	pDC->SetViewportOrg(r.right/2,r.bottom/2);
	pDC->SetViewportExt(r.right,r.bottom);

	double x,y;
	for (x=-100.0; x<100.0; x++){
		pDC->MoveTo((int)(x*10),-1000);pDC->LineTo((int)(x*10),1000);
		pDC->MoveTo(-1000,(int)(x*10));pDC->LineTo(1000,(int)(x*10));
		y=x*x/100;
		pDC->SetPixel((int)x,(int)y,0);
	}
}

黄色の部分以外は、先ほどと同じです
SetMapMode(MM_ANISOTROPIC) は、任意の単位を使うというものです。
今回のようにスケールを変えて、拡大(縮小)するときには必要です。

SetWindowExt(200,200) で、論理座標のウィンドウを(0,0)〜(200,200)に
しています。
それに対して、SetViewportExt(r.right,r.bottom) で
ビューポートの大きさをウィンドウ全体にしています。

ここで、(ウィンドウ):(ビューポート)の比が成り立っています。
デフォルトでは、両方とも1なので、1:1になります。
片方の関数を忘れてしまうととんでもない比になってしまうので
両方いることを常に念頭に置いてください。
また、引数は整数である必要があります。

原点の補足ですが、論理座標のウィンドウの原点も設定ができます。
SetWindowOrg(100,100) とするとウィンドウの原点が論理座標に対して
(100,100)に定まります。
したがって、これを今のコードに加えると全体的に左上に(100,100)だけ移動します。

上上へ


2,起動時の設定

サイズ

WindowのサイズはPreCreateWindow関数で起動時のサイズを設定することができます。

クラス メッセージ メンバ関数
CMainFrame PreCreateWindow

BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
	cs.x=100;
	cs.y=200;
	cs.cx=300;
	cs.cy=400;
	cs.style=WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU;

	return CFrameWnd::PreCreateWindow(cs);
}

これは、スクリーン座標の(100,200)に幅300ドット、高さ400ドットの
Windowをつくるというものです。
スタイルはこの状態ではユーザーがサイズ変更のできない、最大、最小化ボタンのない
Windowをつくります。

Windowスタイル 意味
WS_THICKFRAME サイズ変更が可能
WS_MINIMIZEBOX 最小化ボタンを持つ
WS_MAXIMIZEBOX 最大化ボタンを持つ

色の設定はCViewクラスのコントラスタで行うことにします。

クラス メッセージ メンバ関数
CTestView CTestView
CTestView ~CTestView

CTestView::CTestView()
{
	static int txt[]={COLOR_WINDOW,COLOR_WINDOWTEXT,COLOR_BTNTEXT};
	static DWORD col[]={RGB(0,0,0),RGB(0,255,0),RGB(0,255,255)};
	SetSysColors(3,txt,col);
}

CTestView::~CTestView()
{
	static int txt[]={COLOR_WINDOW,COLOR_WINDOWTEXT,COLOR_BTNTEXT};
	static DWORD col[]={RGB(255,255,255),RGB(0,0,0),RGB(0,0,0)};
	SetSysColors(3,txt,col);
}

これは、コントラスタでWindowの色を黒、テキストの色を緑色
ボタンの色を水色にします。
但し、これはシステムに対しての命令なのでこれを実行すると
他のWindowまで変わってしまいます。そこでこのアプリの実行を終了すると
元の色に戻しています。

●メッセージを使う方法

CFormViewクラスの場合、メッセージに「WM_CTLCOLOR」というものがあります。
これは色を配色する際に読み出されるものです。

クラス メッセージ メンバ関数
CTestView WM_CtlColor OnCtlColor

HBRUSH CNamaeView::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) 
{
	HBRUSH hbr = CFormView::OnCtlColor(pDC, pWnd, nCtlColor);
	
	if (nCtlColor==CTLCOLOR_DLG)
		return CreateSolidBrush(RGB(0,0,0));
	
	return hbr;
}

nCtlColorはコントロールのタイプを識別するものです。
ここでは、ダイアログのバックを変えたいのでCTLCOLOR_DLGの時にだけ黒にします。
他にも以下のようなものがあります。

CTLCOLOR_BTN ボタン コントロール
CTLCOLOR_DLG ダイアログ ボックス
CTLCOLOR_EDIT エディット コントロール
CTLCOLOR_LISTBOX リスト ボックス コントロール
CTLCOLOR_MSGBOX メッセージ ボックス
CTLCOLOR_SCROLLBAR スクロール バー コントロール

上上へ


戻るC++のPageに戻る