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に戻る