動作環境:Win XP Pro
開発環境:VS2005 VC++(MFC)
MDIを使用してアプリケーションを作成しようと考えています。
やりたいこと
・2種類の子画面を用意(子画面①、子画面②)
・起動時には親画面の中に子画面①のみ表示される
・子画面①にボタンを配置し、ボタンを押下すると子画面②が表示される
イメージに近いものとしては、
http://www.alpha-net.ne.jp/users2/uk413/vc/VCT_MDI1.html
こちらのサイトで解説されているやり方は、アプリ起動時に2つの画面が同時に起動しま
すが、
私はあくまでも、ボタンを押したら子画面②が表示される、というものを作成しようとし
ています。
サイトや掲示板を探しましたが、なかなかやりたいことに近いものが見つけられずに困っ
ています。
やり方をご存知の方、または解説しているサイト等ございましたら、教えていただけます
でしょうか?
よろしくお願いします。
ちゃんとは読んでいませんが、やり方は提示されたHP内に書いてあると思います。
今回はボタンが押されたタイミングでCreateNewFrame()で子ウィンドウを表示するようにすればOK
です。
ただ新規ウィンドウを表示するときに、新規ウィンドウを作成するときに聞いてくるダイアログが出
てしまうので、これを消すようにしないといけないですね。
で、やり方は… 今 過去のソースを見てますので、しばしお待ちを。。。
提示されたHPに新規ウィンドウを出さない方法は書いてありましたね。
リソースを修正すれば良いようです。(何せ数年前にやったので忘れてました)
これ以上は、もう少し具体的にどこがわからないのかはっきりさせてもらわないと答えられませ
ん。。
いろはさん、ありがとうございます。
具体的につまづいている箇所を書いていませんでした。
申し訳ありません。
HPのサンプル通りに作成し、まずは起動時の同時表示をしました。
ステップ実行を行い、子画面②を表示させている処理はわかりました。
それをボタンのコントロールの箇所で行えば良いだろう、というところまでは行き着きま
した。
起動時に子画面②が起動しないように、サンプルに記載されていた、
・テンプレートの記述
・pMainFrame->OpenView(pDocTemplate2);
をコメントアウトし、ボタンが押下されたところの処理を、以下のように記述し、コンパ
イルしました。(コンパイルは問題なかったです)
void CxxxView::OnBnClickedButton1()
{
CMultiDocTemplate* pDocTemplate2 = new CMultiDocTemplate(
IDR_xxxTYPE2,
RUNTIME_CLASS(CxxxDoc),
RUNTIME_CLASS(CChildFrame), // カスタム MDI 子フレーム
RUNTIME_CLASS(CxxxView2));
CMainFrame* pMainFrame = new CMainFrame;
pMainFrame->OpenView(pDocTemplate2);
}
実行すると、起動時には親画面の中に子画面①だけが表示されました。
しかし、子画面①のボタンを押すと、
xxx.exeの 0x00413cd9 でハンドルされていない例外が発生しました:
0xC0000005: 場所0x00000000 を読み込み中にアクセス違反が発生しました。
というメッセージが表示され、エラーになってしまいます。
ステップ実行してみると、OpenView関数内の
CDocument* pDoc = MDIGetActive()->GetActiveDocument();
で落ちているようなのですが・・・。
過去のソースはあるのですが、動くソースが無いので確かなことは言えませんが。。。
MFCのソース内にステップ実行すれば何が悪いのかわかるかもしれませんよ。
予想で書きますが、CreateしたMultiDocTemplateをAddDocTemplate()していないのが原因かと思
います。
HPに書いてあったようにCXXApp::InitInstance()内でMultiDocTemplateをCreateして
AddDoctemplate()したらどうでしょうか。
いろはさんも書いておられますが
> CMultiDocTemplate* pDocTemplate2 = new CMultiDocTemplate(
> IDR_xxxTYPE2,
> RUNTIME_CLASS(CxxxDoc),
> RUNTIME_CLASS(CChildFrame), // カスタム MDI 子フレーム
> RUNTIME_CLASS(CxxxView2));
普通これは、CXXApp::InitInstance()内で書きます。
通常、MDIでスケルトンを作成すれば、下記の様な者をVCが作ってくれます。
------ ココカラ -------
CMultiDocTemplate* pDocTemplate;
pDocTemplate = new CMultiDocTemplate(IDR_xxx,
RUNTIME_CLASS(CxxxDoc),
RUNTIME_CLASS(CChildFrame), // カスタム MDI 子フレーム
RUNTIME_CLASS(CxxxView));
if (!pDocTemplate)
return FALSE;
AddDocTemplate(pDocTemplate);
------ ココマデ -------
後は、
コピーして
登録するドキュメントテンプレート pDocTemplate
表示させたいメニュ- IDR_xxx
ウインドウのクラス CxxxDoc、CChildFrame、CxxxView
を変更してして
表示したいウインドウ分作ります。
追記
あと
> CMainFrame* pMainFrame = new CMainFrame;
> pMainFrame->OpenView(pDocTemplate2);
は、
CXXApp内じゃないと実行できないです。
pDocTemplate2をnewしているのはCXXApp内なのでViewで実行したい時は、
PostMessage/SendMessage等でメッセージをCXXAppに送るなりしないと駄目かもしれませ
んね。
theAppがグローバルになっているから使えるかも知れませんが、僕は前者を進めます
が。
追記2
HP内
>\nMDITes\n\n\n\nMDITest1.Document\nMDITes Document
これもウインドウ分追加しないといけないはずです。
MDITesが確かテンプレート名
いろはさん、ITOさん、ありがとうございます。
お二人が仰る通り、CxxxApp::InitInstance()内でMultiDocTemplateをCreateして
AddDoctemplate()しました。
また、HPやITOさんの仰る通り、
リソースビュー -> String Table -> String Table
のIDR_xxxTYPEをコピー&ペーストし、
IDR_xxxTYPE2 \nxxx\n\n\n\nxxx.Document\nxxx.Document
を追加しました。
その上で、子画面①のボタンが押されたところでSendMesasgeで子画面②を呼び出そうと思い、
void CxxxView::OnBnClickedButton1()
{
// TODO: ここにコントロール通知ハンドラ コードを追加します。
GetParent()->SendMessage(WM_COMMAND, IDR_xxxTYPE2);
}
と記述し、実行したのですが、子画面②が表示されませんでした。
GetParent()->SendMessage(WM_COMMAND, ID_FILE_NEW);
や
GetParent()->SendMessage(WM_COMMAND, ID_APP_ABOUT);
とすると、子画面①やバージョン情報ダイアログは開くのですが・・・。
> GetParent()->SendMessage(WM_COMMAND, IDR_xxxTYPE2);
↑これじゃダメじゃないかな。。
もしやるならIDR_XXXTYPE2をID_FILE_NEWにしないと。でもこれだと子ウィンドウ1が出てしまいま
すけどね。
アプリケーションクラスにOpenChild2とか作って、この関数内でDocTemplateを検索
(CWinApp::GetFirstTemplatePositionとCWinApp::GetNextDocTemplateを使用)し
て、CreateNewFrameすれば良いと思います。
たとえば、、
CWinApp::OpenChild2()
{
// GetFirstTemplatePositionとGetNextDocTemplateを使って
//
}
途中で送っちゃった…
CxxxApp::OpenChild2( CDocument* pDoc )
{
CDocTemplate* pTemplate;
// GetFirstTemplatePositionとGetNextDocTemplateを使って
// 対象とするテンプレートを取得
CMDIChildWnd* pNewFrame = (CMDIChildWnd*)pTemplate->CreateNewFrame(pDoc,
NULL);
if( pNewFrame )
pTemplate->InitialUpdateFrame(pNewFrame, pDoc);
}
void CxxxView::OnBnClickedButton1()
{
((CxxxApp*)AfxGetApp())->OpenChild2( GetDocument() );
}
こんな感じ。
いろはさん、返事が遅くなり申し訳ありませんでした。
いろはさんからのヒントを元に、
void CxxxApp::OpenChild2(CDocument* pDoc)
{
CWinApp* pApp = AfxGetApp();
POSITION pos = pApp->GetFirstDocTemplatePosition();
CDocTemplate* pTemplate;
while (pos != NULL)
pTemplate = pApp->GetNextDocTemplate(pos);
CMDIChildWnd* pNewFrame = (CMDIChildWnd*)pTemplate->CreateNewFrame(pDoc, NULL);
if(pNewFrame)
pTemplate->InitialUpdateFrame(pNewFrame, pDoc);
}
と記述して実行したところ、こちらの意図する動きをしてくれました。
いろはさん、ITOさん、本当にありがとうございました。