開発環境はwindowsXp VC++2005Sp1 MFC SDIで行っております。
作成したいことは、下記の内容になりますが、実際には難しく困っております。
最終目標:VC++でダイアログ上にコントローラを貼り付けるよう動作を
プログラムにて作成したい。
その過程で、ダイアログバーより、作成するコントローラをダイアログに貼り付ける
のですが、デザインモードと実行モードを切り分けたく。
デザインモード中は、コントローラの移動、リサイズを可能にし、
実行中は、コントローラの実行のみを行いたく思っております。
そこで現在デザインモードについて思考中なのですが、
デザインモード中は、各コントローラを表すビットマップをダイアログ上に
貼り付けて、移動、リサイズを可能にしたいと思っております。
まずは、このような動作を行う場合で、何かしらのコントローラにビットマップを
割付たいのですが、どのようにしたら実現できるかわかりません。
説明が拙くてわかりにくいと思いますが、どうかご教授いただけないでしょうか?
とりあえず、コントロール(ボタン)にビットマップ貼り付け。
http://www.athomejp.com/goldfish/mfc/button/setbitmap.asp
# 最終目標の道のりはかなり長そうですよ。
# 本当にやる必要があるか、何度か立ち止まって考えると良いと思います。
コントロールの間違いですよね、多分。
コントロールのイメージをビットマップでどうにかすると言う話ですが、
移動はともかく、サイズの変更はどうするのだろうと思ったり。
単純にコンボボックスのビットマップを拡大してしまうとリストボックスを
表示させる為のボタンが変形してしまうとかそういう不都合が起こりそうです。
思うに結構面倒そうです。
かえってビットマップにするよりも自前で簡易描画した方が楽そうです。
たいちうさんの言われる通り、本当に必要がある処理なのか考え直した方が
良いかもしれません。苦労の割には結果が伴わないかも。
ご回答ありがとうございます。
何も進まないままになってます(>_<)。
まず、VCのコントロールのようにダイアログに貼り付け、
コントロールを選択した場合に
①コントロールの周りに変更枠を出す。
②カーソルが変更する
上記を試みているのですが、①は絶望的に案がなく②も試しているのですが
うまくいきません。
//-----------------------------
// カーソルの変更
//-----------------------------
HCURSOR cusor =(HCURSOR)LoadImage(NULL,
MAKEINTRESOURCE(IDC_*****),
IMAGE_CURSOR,
0,
0,
LR_DEFAULTSIZE | LR_SHARED);
this->SetCursor(cusor);
①・・・ダイアログに直書きすると意外に楽かもしれません
②・・・コードは間違えてはいないかと思います。
エラーチェックしてみてください。
現在上記処理をダイアログに貼り付けたコントロールの中でやっておりますが、
カーソルの変更には、親のダイアログにて行う必要がありますか?
親のダイアログに渡して行ったら、変更されました。
ありがとうございます。
①コントロールの周りに変更枠を出す
上記って、可能なのでしょうか、具体的な案が思い出せず、苦しんでます。(>_<)
どうかご教授いただけないでしょうか?
WM_SETCURSOR ならボタンなどのコントロール上でも送られてくるみたいなので、そこで枠の表
示や、カーソルの変更などをすると良いと思います。
BOOL CXXXDlg::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
{
CRect rect;
CClientDC dc(this);
CBrush frame_brush, erase_brush; // 毎回使うのでメンバにしても良いと思います
CPoint point;
if(!m_bEdit) return TRUE; // 編集モードじゃなければ何もしない
switch(message){
case WM_LBUTTONDOWN :
break;
case WM_RBUTTONDOWN :
if(pWnd != this){
m_bDrag = TRUE;
}
break;
case WM_RBUTTONUP :
if(m_bDrag)
m_bDrag = FALSE;
break;
case WM_MOUSEMOVE :
if(m_pFucos != this && m_bDrag){
サイズ、位置の変更
}
// 別のコントロールの上にカーソルが移動したら、上から塗りつぶして枠を消す
if(pWnd != m_pFocus && m_pFocus != this)
{
// ダイアログ領域の色のブラシを作成
erase_brush.CreateSysColorBrush(COLOR_BTNFACE);
// ボタンなどのコントロールに外接する四角形の取得
m_pFocus->GetWindowRect(&rect);
// GetWindowRectはScreen上での座標を返すのでダイアログ上の座標に変更
this->ScreenToClient(&rect);
rect.InflateRect(3, 3, 3, 3);
// 以前の選択枠の上に書いて、選択枠を消す
dc.FrameRect(&rect, &erase_brush);
SetCursor(m_hArrow);
m_Mode = NON;
}
// ボタンなどのコントロール上なら選択枠を描く
if(pWnd != this){
// 枠様のブラシを作成
frame_brush.CreateStockObject(BLACK_BRUSH);
pWnd->GetWindowRect(&rect);
ScreenToClient(&rect);
// 選択枠を表示するために適当に枠を広げる
rect.InflateRect(3, 3, 3, 3);
// 選択枠を表示
dc.FrameRect(&rect, &frame_brush);
// マウスカーソルの位置を取得(この関数もスクリーン座標で返される)
GetCursorPos(&point);
this->ScreenToClient(&point);
// 適当に枠を縮めて枠の外に出たら、サイズ変更カーソルを表示
rect.InflateRect(-6, -6, -6, -6);
if(point.x < rect.left || point.x > rect.right){
SetCursor(m_hWSize); // 幅変更カーソル
}
else if(point.y < rect.top || point.y > rect.bottom){
SetCursor(m_hHSize); // 高さ変更カーソル
}
else{
SetCursor(m_hCursor); // コントロール上用のカーソル
}
}
else{
SetCursor(m_hArrow); // コントロール上に無ければ標準カーソルを表示
}
m_pFocus = pWnd; // カーソルの下にあるコントロールのポインタをメンバにセット
}
return TRUE; // デフォルト処理でカーソルの変更をされないようにTRUEを返す
//return CDialog::OnSetCursor(pWnd, nHitTest, message);
}
初期化で、カーソルのハンドルの設定、と標準カーソルのセット(カーソル処理を無効化してい
るため)m_pFocus に this を設定しおいてください。
右ドラッグ中に、SetWindowPos でサイズや、位置の変更をしてやると良いと思います。
左クリックをするとボタンがへこんでしまうので、右クリックを使ったほうが簡単だと思いま
す。オーナードローでへこまないようにも出来ますが、ボタンなどの表示を全部自分で書かない
といけないので、大変です。
やや強引なやり方かもしれないので、参考までにしてください。
それから、VC++6.0 で試しただけなので、2000 では仕様が変わっているかもしれません。
訂正
case WM_RBUTTONDOWN :
if(m_pFocus != this){
m_bDrag = TRUE;
}
break;
// 別のコントロールの上にカーソルが移動したら、上から塗りつぶして枠を消す
if(pWnd != m_pFocus && m_pFocus != this)
{
Invalidate();
}
再描画をしたほうが簡単、かつ綺麗に枠が消えます。
ありがとうございます。
早速試してみます。
思うんですが、何処まで編集中の表示に凝るか次第だと思います。
編集モードでは、コントロールの種類が判別できる程度の簡易描画を
行うようにしておいて各コントロールの種類の応じてサイズから
そのコントロールの簡易表示を描画するような関数を用意しておいて
編集中はその簡易表示で対応する。
で、VCのリソースエディタのテスト表示のような感じで実際のイメージ表示と
分けて考えてしまった方がシンプルになりそうな気がします。
実際のコントロールを使ってしまうとどうしても通常のクリック時の動作まで
再現してしまいますから派生クラス使って既存の処理を潰しておいて
編集時にはそっちのクラスでサブクラス化するとかしないとうまくいかないのでは無いか
なぁ。
枠の話ですけれど、各コントロールはウインドウサイズとコントロールのサイズが
同じですからコントロール内でウインドウサイズの外には描画できないのではないかなと。
ウインドウサイズの内側にコントロールに多少かかる形であれば、描画も可能ではないか
と思います。
コントロールに掛かるのが気に入らないなら親ウインドウのクライアント領域にコント
ロールを
囲むように描画しないと表示されないのではないでしょうか?
あと、コントロールに対してGDIで描画処理をしても領域が無効化されていないと
描画処理が画面に反映されないと思います。
これは、Windowsでは割と基本的な話なので抑えておいた方がよろしいかと。
画面を更新したい場合は、更新したい領域が無効化されている必要があります。
枠については、なんとかそれらしくコントロールの隅に■の選択枠を出すようにして、
そこの座標にマウスが乗った場合にマウスを変更するようにしました。
とりあえず、前準備としては、それらしくなりました。
次は、下記に取り組みと考えております
①選択された状態でリサイズされた場合
②選択された状態で移動された場合
①②とも、マウスを押下している状態を管理して、コントロールを移動/リサイズ
させるのではなくて、VCのように点線のラインで引っ張りだして、確定した状況。
マウスを離した状況で、実際のコントロールの移動をしようと考えております。
■の線は、dc.FrameRect(&rect, &erase_brush);
を参照して8つ書いたのですが、点線とかもできるのでしょうか?
長々となりましたが、皆様のおかけでちょっとづつ進んで参りました。
また、お世話になりますが、ご教授ください。
宜しくお願い致します。(^_^)
例えばこんなのかな?
CRect rect(50, 50, 100, 100);
CPen pen(PS_DOT, 1, RGB(0, 0, 0));
dc.SelectObject(&pen);
dc.SetBkColor(GetSysColor(COLOR_BTNFACE));
dc.SelectStockObject(NULL_BRUSH);
dc.Rectangle(rect);
dc.SelectStockObject(BLACK_PEN);
たいちろうさん、ありがとうございます。
なんとかそれっぽく、見えるように近づきました。
ただ、なにぶん初心者で、点線の残像の消し方がわかりません。
塗りつぶしたり、いろいろ試したのです。
RedrawWindowやUpdateWindowとかを使用するのでしょうか。
度々申しあけありません。また、ご教授ください。(>_<)