超初心者さん
たぶん伝わっていないと思うので,もう一度説明します.
私のやりたいことは,
例えばダイアログの左にピクチャA,右にピクチャBがあるとすると,ピクチャBのダイアログの
大きさで,ピクチャBだけを表示したいということです.
表示させる場所は関係なく,表示させる部分と大きさを指定したいのです.
ただ大きさを変えた(小さくした)だけでは,必然的にダイアログの左上部分がの表示されま
す.
これを例えばダイアログの右下部分が残るようにしたいのです.
PATIOさんが仮想的に右下の座標を原点とすれば出来るとアドバイスされていたのですが,
具体的な方法がわからないんです...
やりたいことはすでに伝わってると思いますよ。
具体的には超初心者さんの方法で実現できると思います。
あと、もうひとつの方法としては、
OnInitDialog()にて、ダイアログのウィンドウサイズを記憶しておく。
OnSize()にて、ダイアログの新しいウィンドウサイズと以前のサイズから
変位量を求め、その分だけ各コントロールの位置をずらしてやれば良い。
アプローチが違うだけで、やってることは同じですが。
…いや、違うのか?
> 表示させる場所は関係なく,表示させる部分と大きさを指定したいのです.
必ずしも右下というわけではないのですね。
そうであれば、やはりOnInitDialog()で各コントロールの位置を記憶する必要がある。
表示させる部分の左上座標を CPoint point;
大きさを CSize size;
コントロールの初期位置を CPoint m_ctrlPos;
とするならば、
void CXXXDialog::ShowArea(CPoint point, CSize size)
{
// コントロールの移動
ctrl->SetWindowPos(NULL,
m_ctrlPos.x - point.x, m_ctrlPos.y - point.y,
0, 0, SWP_NOSIZE|SWP_NOZORDER);
...
// ダイアログのサイズ変更
SetWindowPos(NULL, 0, 0, size.cx, size.cy, SWP_NOMOVE|SWP_NOZORDER);
}
つまり、こういうことがやりたい?
要は、表示対象になっている物が大きな板の上に載っているとして
それをウインドウの大きさの窓から覗いていると考えればよいのでは?
任意の場所が表示されるようにする為には窓が覗く位置を任意に調整すれば、
良いわけですから、それを元に実際のクライアント座標上の位置を計算すれば良い。
ウインドウをコントロールする時の座標はクライアント座標系になるので
それを算出するわけです。
この辺の話って紙に書いてみれば直ぐにイメージが湧くと思うんだけどなぁ。
クライアント座標の原点が大きな板の上の座標系でどの位置になるかを考えて
それぞれのコントロールの位置をクライアント座標で表すとどうなるかっていう話です。
通常は大きな板の原点とウインドウ座標の原点は一致しているので
ウインドウサイズを変えれば、右下の方から画面外になりますよね。
何もしなければ、この関係は変わらないわけですからそうなるの当たり前です。
で、これを任意に動かすような便利な仕組みは用意されていないので
何とかしようすると自前で座標計算をしないと駄目と。
計算そのものは簡単な算数レベルの物なのでちゃんと概念が理解できていれば、
自分でもできるはずです。
逆に計算方法を聞かないとわからないというのは概念を理解できていないと言う事なので
概念の理解からかかった方がよいと思います。
概念の理解無しに計算方法だけわかっても応用が全く利かないので。
>やりたいことはすでに伝わってると思いますよ。
そう思います
基本的には超初心者さんの方法で実現できると思います。
youさん 仮にダイアログがクライアント領域になにもないのっぺらぼうなものだったら
なにも問題ないですよね 要するにコントロールがのっかっているから問題が
起こるわけです ダイアログを変形したとき隠れてしまったり希望の位置にならなくて
困るコントロールがあるならそれを希望の位置へ動的に配置換えすればよいわけです
その計算は座標の単なる加減算だということです
実例をつくってみました(私のシステムでは正常に動きます)
仮定
(1)ダイアログにはボタン(OKとBUTTON1,BUTTON2)とエディットボックスがある
(2)それぞれIDはIDOK IDC_BUTTON1 IDC_BUTTON2 IDC_EDIT1
(3)OKを押すとダイアログの幅が半分に変形する
(4)変形後OK,BUTTON1,BUTTON2はダイアログに残しEDIT1は外に隠す
コメント
(1)変形後残すものは変形前は左半分にあっても右半分にあってもよい
(2)コントロールが多数あるときは個別部分のところは
WM_APPを使ってIDを連番にすればfor文が使用できます
void CDtestDlg::MoveOut(
int ID,int NewX, int NewY, int NewWidth, int NewHeight,int d){
CRect Ctrl;int x1, x2, y1, y2;
CWnd* pWnd = GetDlgItem(ID);
pWnd->GetWindowRect( Ctrl );
x1 = Ctrl.left; x2 = Ctrl.right; y1 = Ctrl.top; y2 = Ctrl.bottom;
if(x1 > NewX && x1<(NewX+NewWidth) ){
pWnd->MoveWindow(NewX+10, y1,x2-x1,y2-y1,1);
}
}
void CDtestDlg::MoveIn(
int ID,int NewX, int NewY, int NewWidth, int NewHeight,int d){
CRect Ctrl;int x1, x2, y1, y2, jd;
CWnd* pWnd = GetDlgItem(ID);
pWnd->GetWindowRect( Ctrl );
x1 = Ctrl.left; x2 = Ctrl.right; y1 = Ctrl.top; y2 = Ctrl.bottom;
if(x1>(NewX+NewWidth)){jd = x1 - (NewX+NewWidth);}else{jd = x1 -
NewX;}
pWnd->MoveWindow(jd-3, y1-NewY-(d - 3),x2-x1,y2-y1,1);
}
void CDtestDlg::OnOK()
{
//共通部分(ダイアログ変形)
CRect Dlog,Client;
int x1, x2, y1, y2, ID,NewX,NewY,NewWidth,NewHeight,d;
GetWindowRect( Dlog ); GetClientRect( Client );
x1 = Dlog.left; x2 = Dlog.right; y1 = Dlog.top; y2 = Dlog.bottom;
NewX = x1; NewY = y1; NewWidth = (x2-x1)/2; NewHeight = y2-y1;
MoveWindow(NewX, NewY, NewWidth, NewHeight, TRUE);
d = y2 - y1 - Client.bottom;
//個別部分(コントロールの移動)
ID = IDOK;
MoveIn(ID,NewX, NewY, NewWidth, NewHeight,d);
ID = IDC_BUTTON1;
MoveIn(ID,NewX, NewY, NewWidth, NewHeight,d);
ID = IDC_BUTTON2;
MoveIn(ID,NewX, NewY, NewWidth, NewHeight,d);
ID = IDC_EDIT1;
MoveOut(ID,NewX, NewY, NewWidth, NewHeight,d);
//CDialog::OnOK();
}
aharenさん
ありがとうございます!
これを参考にプログラムを組んでみます!
結果は出来次第報告いたします.
改良版です
変形用のボタンOKが右上にあるとの仮定で右上を基準に
すべてのコントロールを平行移動する例です
変形はどんな変形でもOKです
個別部分の手数の節約については改良の余地が大です
void CDtestDlg::MoveCtrl(
int ID,int NewX, int NewY, int NewWidth, int NewHeight,
int OldX, int OldY, int OldWidth,int OldHeight,int d){
CRect Ctrl;int x1, x2, y1, y2, DiffX,DiffY;
CWnd* pWnd = GetDlgItem(ID);
pWnd->GetWindowRect( Ctrl );
x1 = Ctrl.left; x2 = Ctrl.right; y1 = Ctrl.top; y2 = Ctrl.bottom;
DiffX = NewX + NewWidth - (OldX + OldWidth);
DiffY = NewY - OldY;
//右下基準の場合は DiffY = NewY + NewHeight - (OldY + OldHeight);
pWnd->MoveWindow(x1 - OldX + DiffX -3, y1 - OldY + DiffY -(d - 3),
x2-x1,y2-y1,1);
}
void CDtestDlg::OnOK()
{
//共通部分(ダイアログ変形)
CRect Dlog,Client;
int x1, x2, y1, y2, ID,NewX,NewY,NewWidth,NewHeight,
OldX,OldWidth,OldY,OldHeight,d;
GetWindowRect( Dlog ); GetClientRect( Client );
x1 = Dlog.left; x2 = Dlog.right; y1 = Dlog.top; y2 = Dlog.bottom;
NewX = x1; NewY = y1; NewWidth = (x2-x1)/2; NewHeight = y2-y1;
OldX = x1; OldWidth = x2-x1; OldY = y1; OldHeight = y2-y1;
MoveWindow(NewX, NewY, NewWidth, NewHeight, TRUE);
d = y2 - y1 - Client.bottom;
//個別部分(コントロールの移動)
ID = IDOK;
MoveCtrl(ID,NewX, NewY, NewWidth, NewHeight, OldX, OldY, OldWidth,
OldHeight, d);
ID = IDCANCEL;
MoveCtrl(ID,NewX, NewY, NewWidth, NewHeight, OldX, OldY, OldWidth,
OldHeight, d);
ID = IDC_EDIT1;
MoveCtrl(ID,NewX, NewY, NewWidth, NewHeight, OldX, OldY, OldWidth,
OldHeight, d);
ID = IDC_EDIT2;
MoveCtrl(ID,NewX, NewY, NewWidth, NewHeight, OldX, OldY, OldWidth,
OldHeight, d);
ID = IDC_BUTTON1;
MoveCtrl(ID,NewX, NewY, NewWidth, NewHeight, OldX, OldY, OldWidth,
OldHeight, d);
ID = IDC_BUTTON2;
MoveCtrl(ID,NewX, NewY, NewWidth, NewHeight, OldX, OldY, OldWidth,
OldHeight, d);
ID = IDC_BUTTON3;
MoveCtrl(ID,NewX, NewY, NewWidth, NewHeight, OldX, OldY, OldWidth,
OldHeight, d);
ID = IDC_BUTTON4;
MoveCtrl(ID,NewX, NewY, NewWidth, NewHeight, OldX, OldY, OldWidth,
OldHeight, d);
//CDialog::OnOK();
}
追)
(1)pWnd->MoveWindow(x1 - OldX + DiffX -3, y1 - OldY + DiffY -(d - 3),
x2-x1,y2-y1,1);
ここにある 3 は線の太さに相当します(この表現適切かどうかはわからない)
(2)d = y2 - y1 - Client.bottom;
タイトルバーの高さです
(3)NewX, NewY, NewWidth, NewHeightと
OldX, OldY, OldWidth,OldHeightとこの例では一致する部分ありますが
どんな変形にも対応できるようにNewとOld両方もうけました
追)
スタッティクメッセージは放っておくとIDは一律IDC_STATICになりますが
これは適当に
IDC_STATIC1
IDC_STATIC2
・・・・
などと個別特定できるように変えます
もちろんもっとわかりやすいID名でもよいです
追)
起動後に変位量の自由な設定について
たとえばgooの地図サイトで地図の上のポイントをダブルクリックすると
そこが中心になるように画面が移動します この手法をもとに
つぎの三つがかんがえられます
(1)上記のようにダブルクリックする点が中心になる(ダイアログは位置も大きさも不
変)
(2)ダブルクリックする点が右下の角の点になる
(3)ダブルクリックする点を通る直線が右辺になる
そこで(1)の実例を作ってみました(2)(3)は必要なら応用してできると思います
void CDtestDlg::MoveCtrl(){
CRect Ctrl;int x1, x2, y1, y2, DiffX,DiffY;
CWnd* pWnd = GetDlgItem(ID);
pWnd->GetWindowRect( Ctrl );
x1 = Ctrl.left; x2 = Ctrl.right; y1 = Ctrl.top; y2 = Ctrl.bottom;
DiffX = (BottomRightX-TopLeftX)/2 - DbClickX; //コントロールの
変位量
DiffY = (BottomRightY-TopLeftY)/2 -
(TbarHeight - 3 + DbClickY);
//コントロールの変位量
pWnd->MoveWindow(x1 - TopLeftX + DiffX -3,
y1 - TopLeftY + DiffY -(TbarHeight - 3),x2-x1,y2-y1,1);
}
void CDtestDlg::OnLButtonDblClk(UINT nFlags, CPoint point)
{
// TODO: この位置にメッセージ ハンドラ用のコードを追加するかまたはデフ
ォルトの処理を呼び出してください
//共通部分(ダイアログ変形)
CRect Dlog,Client;
GetWindowRect( Dlog ); GetClientRect( Client );
TopLeftX = Dlog.left; BottomRightX = Dlog.right;
TopLeftY = Dlog.top; BottomRightY = Dlog.bottom;
DbClickX = point.x; DbClickY = point.y;
Invalidate();
TbarHeight = BottomRightY - TopLeftY - Client.bottom;
//個別部分(コントロールの移動)
ID = IDOK; MoveCtrl();
ID = IDCANCEL; MoveCtrl();
for(ID = 1009;ID < 1021; ID++){ MoveCtrl();}
CDialog::OnLButtonDblClk(nFlags, point);
}
引数を渡す方法でなくメンバー変数(データメンバーがC++の正式呼び名かな?)
ダイアログクラスの中でを定義しました
// 構築
public:
int TopLeftX; //ダイアログの左上X座標
int TopLeftY; //ダイアログの左上Y座標
int BottomRightX; //ダイアログの右下X座標
int BottomRightY; //ダイアログの右下Y座標
int DbClickX; //ダブルクリック点X座標
int DbClickY; //ダブルクリック点Y座標
int TbarHeight; //タイトルバーの高さ
int ID; //コントロールのID
void CDtestDlg::OnLButtonDblClk(UINT nFlags, CPoint point)
この関数はメニューにある 表示 から Classwizard をたどり
WM_LBUTTONDBCLK というイベントに関数をつけます
コントロールはOKとキャンセルのほかに
STATIC EDIT BUTTON COMBO をそれぞれ3個づつつくりました
システムが自動的に割り振った各コントロールのID値は
Resource.hのなかにあり
#define IDC_STATIC1 1009
#define IDC_STATIC2 1010
#define IDC_STATIC3 1011
#define IDC_EDIT1 1012
#define IDC_EDIT2 1013
#define IDC_EDIT3 1014
#define IDC_BUTTON1 1015
#define IDC_BUTTON2 1016
#define IDC_BUTTON3 1017
#define IDC_COMBO1 1018
#define IDC_COMBO2 1019
#define IDC_COMBO3 1020
なのでfor文は for(ID = 1009;ID < 1021; ID++){ MoveCtrl();}
にしました ただしこれはビルド押す前に確認する必要があります
コントロールを途中で削除なんかすると連番でなく欠番が生じる
こともあります 事実私のシステムでも最初は1000からだったのですが
削除追加したので上記のようにかわってしまいました
みなさんありがとうございます!
aharenさん お陰で無事システム完成することが出来ました.
僕はコントロールを動かせることを知らなかったのでこんなに悩んだのだと思います...
とても分かりやすい解説ありがとうございました!