2003/07/29(火) 18:39:14 の hanabi さんの発言に似ているのですが、
行き詰っているので質問させてください。
MFCベースのSDIアプリケーションで WS_OVERLAPPEDWINDOW な子ウインドウをつくる場合
はどのようにすればよいでしょうか。
hanabi さんの場合は、メインウインドウの中に子ウインドウを作るわけですが、私
は.NET Framework の WindowsForm アプリのように、複数のウインドウに親子関係はあ
っても、包含関係なくデスクトップ上のどこにでもウインドウが位置できるようにした
いのですが、どうすればよいでしょうか。
画像処理ソフトを作っておりまして、親ウインドウ(メニューあり)には処理前画像を表
示し、子ウインドウ(メニューなし、Zオーダ最前面)には処理後画像を表示したいです。
こういうときこそ MDI の出番なのでしょうが、わけあって SDI でウインドウを2個並
べて表示したいのです。
元ネタになっている発言がかなり古いもののようですが、できればリンクを張ってほし
いです。
で、2点、教えてください。
・VisualStudio のバージョンは何ですか?
・全てがメインウィンドウですか?
2点目は、
1:アプリを起動する
2:ウィンドウAが開く
3:ウィンドウBを開く
4:ウィンドウAを閉じる
という操作をした時、アプリは終了するのか、ウィンドウBだけが表示されている状態
で実行が継続されるのか、ということです。
aetosさん、ご返事ありがとうございます。
元ネタは
http://rararahp.cool.ne.jp/cgi-bin/lng/vc/vclng.cgi?print+200307/03070119.txt
のスレッドです。
1点目です。
バージョンは VC++ .NET 2002 です。
すべてがメインウインドウではありません。
メインウインドウと子ウインドウです。
2点目です。
1-2-3-4の動作をすると、アプリは終了します。
ウィンドウAを閉じると、ウィンドウBも閉じます。
今日、会社で色々と試しておりましたがダメでした。
CWnd* MyWnd; とグローバル変数にして
InitInstance部で、下記のようにしても実行時エラーが出たり、
CWnd::CreateEx() の戻り値が 0 になって素通りしたりで、うまくいきませんでした。
BOOL ChogeApp::InitInstance()
{
// メイン ウィンドウが初期化されたので、表示と更新を行います。
m_pMainWnd->ShowWindow(SW_SHOW);
m_pMainWnd->UpdateWindow();
MyWnd = new CWnd();
MyWnd->CreateEx (
0,
0,
Window,
WS_POPUP | WS_VISIBLE, // WS_OVERLAPPEDWINDOW | WS_VISIBLE
CRect( 8, 8, 320, 240 ),
m_pMainWnd->GetParent(), // m_pMainWnd
123
);
}
子ウインドウっていうとWS_CHILDが付いたウィンドウを想像してしまう。
あなたが作りたいのは子ウィンドウではありませんね。
WS_CHILDなしで親ウィンドウにメインウィンドウを指定すれば
メインウィンドウより手前に表示されるし
メインウィンドウが削除されればともに削除されるなど
あなたの希望のものになると思います。
原因はMFCが特定の使い方以外は優しくないから。
MFCの想定外あるいはもしかしたら間違ったことしてるかもしれないということで
WS_CHILDが付いてないとエラーにしている。
CWndそのままでは利用できない。
派生クラスを作る必要あり。
どうやるかは知らない。
もしかして、こんなやつ?
WNDCLASS Wc;
memset(&Wc, NULL, sizeof(WNDCLASS));
Wc.lpfnWndProc = AfxWndProc;
Wc.hInstance = AfxGetInstanceHandle();
Wc.hCursor = ::LoadCursor(NULL, IDC_ARROW);
Wc.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;
Wc.lpszClassName = _T(Class);
Wc.hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
Wc.hbrBackground = (HBRUSH)COLOR_BTNSHADOW;
AfxRegisterClass(&Wc);
MyWnd = new CWnd;
MyWnd->CreateEx(0, Wc.lpszClassName, _T(Window),
WS_OVERLAPPEDWINDOW | WS_VISIBLE, CRect(8, 8, 320, 240), m_pMainWnd, 0);
以下でもよさげ
TCHAR ClassName[256];
int nCnt = ::GetClassName(*m_pMainWnd, ClassName, 256);
WNDCLASS Wc;
::GetClassInfo(AfxGetInstanceHandle(), ClassName, &Wc);
MyWnd = new CWnd;
MyWnd->CreateEx(0, Wc.lpszClassName, _T(Window),
WS_OVERLAPPEDWINDOW | WS_VISIBLE, CRect(8, 8, 320, 240), m_pMainWnd, 0);
要は、 CreateEx() の 第2引数の値が NULL(0) じゃ駄目ってこと。
MFCのウィンドウプロシージャは AfxWndProc() ですので指定してください。
最初のサンプルは、AfxWndProc() を指定したウィンドウプロシージャを作成、
今回のサンプルは、メインフレームのウィンドウプロシージャを取得して同じ
ものを指定しているわけです。
あ、クラス名だけ分かればいいから、後者のサンプルはもっと短くなりますね(^-^;
TCHAR ClassName[256];
::GetClassName(*m_pMainWnd, ClassName, 256);
MyWnd = new CWnd;
MyWnd->CreateEx(0, ClassName, _T(Window),
WS_OVERLAPPEDWINDOW | WS_VISIBLE, CRect(8, 8, 320, 240), m_pMainWnd, 0);
以上
大昔に「ポップアップチャイルド」と言われてたやつかも。
基本的にはwclrp ( 'o') さんの言うとおりで、
「MFC + ドキュメントビューアーキテクチャ」を使った段階で
「実現不能」に極めて近いですね。
んで、実現方法としての一本道は、「子と称する窓はSDKで作る」な
わけですが、MFC+DocViewで、むりやりやる方法としては
FrameのPreCreateWindow()でcs.styleを設定して
WNDCLASS wndcls;
GetClassInfo( AfxGetInstanceHandle(), cs.lpszClass, &wndcls);
AfxRegisterWndClass( 0, wndcls.hCursor, wndcls.hbrBackground, NULL);
とやってみる手はあります。
まぁ、MFCのチェックコードとの戦いになりますが、
上手くすり抜けるといけちゃうかもしれませんね。
かなり上級の知識と腕が必要と思われます。
できなかったらあしからず。がんばってください。
WS_CHILD を使わないウィンドウなら、
CWnd の代わりに CFrameWnd を使ってみてはどうかな?
あっとSDIかぁ。もっと普通にできるかも。失礼しました。
モードレスダイアログに画像表示させる
では駄目なんかな?
aetosさんが仰った
>1:アプリを起動する
>2:ウィンドウAが開く
>3:ウィンドウBを開く
>4:ウィンドウAを閉じる
の4実行時にWindowBが残ることを希望って意味であれば
俺なら別アプリにしてしまうかもしれない。
>かなり上級の知識と腕が必要と思われます。
残念ながら自分はこのような知識がないので・・。
>>1:アプリを起動する
>>2:ウィンドウAが開く
>>3:ウィンドウBを開く
>>4:ウィンドウAを閉じる
>の4実行時にWindowBが残ることを希望って意味であれば
これをやるなら
私は、メインアプリウィンドウを隠しておき
ウィンドウAを別個に開いて、メインウィンドウに見せかける方法かな
家に帰って覗いてみたら、皆様がいろいろ書き込んでおられてびっくりしました。
今日も会社でいろいろやってたんですが、ぜんぜんダメでめげておりました。
今、bun さんのコードをやってみたらスンナリコンパイルがとおって、
思ったようなウインドウができ、動作もそのとおりでした。
rinさんのモードレスダイアログに...、
という書き込みも検討してみます。
仲澤さんの方法は難しそうで、
今の私には無理かもしれません。
とりあえず、bunさんをはじめ皆様ありがとうございました。
さて、本スレッドの題名とやや外れてくるのですが、再質問させてください。
(もし新しいスレッドを作ったほうがいいのでしたらご指摘ください)
SDIウインドウのメインのほうは CScrollView の OnDraw で描画をしているのですが、
CreateEx したほうのウインドウは、どこに描画コードを書けばよいのでしょうか?
SDKのメッセージループだと WM_PAINT のところに書けばよいと思いますが、
MFC で CreateEx したウインドウの OnDraw(WM_PAINT) 的なことは
どうすればいいのでしょうか?
/* 動きました、ありがとうございました。****/
BOOL CaaaApp::InitInstance()
{
// いろいろウィザードコードあり。省略.
// メイン ウィンドウが初期化されたので、表示と更新を行います。
m_pMainWnd->ShowWindow(SW_SHOW);
m_pMainWnd->UpdateWindow();
WNDCLASS Wc;
memset(&Wc, NULL, sizeof(WNDCLASS));
Wc.lpfnWndProc = AfxWndProc;
Wc.hInstance = AfxGetInstanceHandle();
Wc.hCursor = ::LoadCursor(NULL, IDC_ARROW);
Wc.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;
Wc.lpszClassName = _T(Class);
Wc.hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
Wc.hbrBackground = (HBRUSH)COLOR_BTNSHADOW;
AfxRegisterClass(&Wc);
MyWnd = new CWnd;
MyWnd->CreateEx(
0,
Wc.lpszClassName,
_T( Window ),
WS_OVERLAPPEDWINDOW | WS_VISIBLE,
CRect(8, 8, 320, 240),
m_pMainWnd,
0
);
m_pMainWnd->SetFocus();
// いろいろウィザードコードあり。省略.
}
ウィンドウクラスでWS_CHILDを回避できるとは知らんかった。
WM_PAINTはOnPaintだよ。
CPaintDC dc(this);を使う規則。