![]()
![]()
| 1,座標 | 3種類の座標 座標2 原点 範囲 |
| 2,起動時の設定 | サイズ 色 |
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になります。
もう一度、座標について復習します。
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)だけ移動します。
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に戻る