親ウィンドウのクライアント領域に、表示されると言う簡単なものです。
ダイアログボックスはどのように作るかというと、CDialogクラスを使います。
まず、このクラスのコンストラクタを見てみます。
最初の引数は、テンプレート名か、IDということになります。 リソースエジタでダイアログプロパティのIDを"MYDLG"のように ダブルクォーテーションで囲むとテンプレート名になります。 囲まなければ単なる整数と見られIDになります。 しかし、MFCの場合はどちらでも結果は同じになります。CDialog::CDialog CDialog( LPCTSTR lpszTemplateName, CWnd* pParentWnd = NULL ); CDialog( UINT nIDTemplate, CWnd* pParentWnd = NULL ); CDialog( );
CDialogクラスから自分のCMyDlgクラスを派生させます。 データメンバにはダイアログボックスの文字列を格納する CStringクラスのm_MyStrを持たせることにします。 また、コンストラクタを書き換えておきます。class CMyDlg : public CDialog { public: CString m_MyStr; CMyDlg(CWnd *pParentWnd = NULL) : CDialog("MYDLG", pParentWnd) {} protected: virtual void OnOK(); };
ところで、CDialogクラスにはOnInitDialog, OnOK, OnCancelハンドラは仮想関数として最初から定義されているので これらの処理をするときにメッセージマップを書く必要はありません。 (書いてもエラーにはならないが意味がない)また、これらを 書き換えた(オーバーライド)時は注意することがあります。 たとえば、OKボタンが押されたときOnOKを自分で書かなければ 単にダイアログボックスが消えるだけです。ところが、 OnOKを書き換えた(エジットコントロールなどの情報を 取得するなど)場合は、最後にEndDialog()関数を呼ぶか CDialog::OnOK()を呼ばなくてはいつまでもダイアログボックスが消えません。
では、ダイアログボックスの呼び出し側(親)ではどうするかというと
というような感じて呼び出します。dlg(this)は最初にMyDlgクラスの定義 を見るとわかるように、"MYDLG"をテンプレートとして、親は「this」です という意味です。DoModal()はモーダルダイアログボックスを起動します。 モーダルダイアログボックスとは「OK」とか「キャンセル」ボタンが 押されるまで親への入力等ができないダイアログボックスです。また、 この戻り値はダイアログボックスの「OK」が押されたらIDOK, 「キャンセル」 が押されたらIDCANCELとなります。ところで、CMyDlgクラスのm_MyStrメンバは publicで宣言しているのでここで取得することができます。CMyDlg dlg(this); dlg.DoModal();
ここでMyMainStrは親のクラスのメンバです。これで、ダイアログボックス のメンバを親のクラスのメンバにコピーできます。(もちろん、OKボタンが 押されたときダイアログボックス側で、m_MyStrに必要な情報を 入れておく必要があります。)CMyDlg dlg(this); if(dlg.DoModal() == IDOK) { MyMainStr = dlg.m_MyStr; }
さて、前置きが長くなりましたがサンプルのプログラムを 見てみることにします。
別に何の変哲もないダイアログとメニューリソースです。// dlg01.rcの一部 自分で書く人は参考にしてください ///////////////////////////////////////////////////////////////////////////// // // Dialog // MYDLG DIALOG DISCARDABLE 0, 0, 115, 61 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "文字列入力" FONT 9, "MS Pゴシック" BEGIN DEFPUSHBUTTON "OK",IDOK,7,39,50,14 PUSHBUTTON "キャンセル",IDCANCEL,58,39,50,14 EDITTEXT IDC_EDIT1,7,7,102,26,ES_AUTOHSCROLL END ///////////////////////////////////////////////////////////////////////////// // // Menu // MYMENU MENU DISCARDABLE BEGIN MENUITEM "ダイアログ(&D)", IDM_DLG END
CMyWindowクラスに表示用文字列のためのMyMainStrをprivateに 宣言しています。// dlg01.h class CMyApp : public CWinApp { public: virtual BOOL InitInstance(); }; class CMyWindow : public CFrameWnd { private: CString MyMainStr; public: CMyWindow(); protected: afx_msg void OnPaint(); afx_msg void OnDlg(); DECLARE_MESSAGE_MAP() }; class CMyDlg : public CDialog { public: CString m_MyStr; CMyDlg(CWnd *pParentWnd = NULL) : CDialog("MYDLG", pParentWnd) {} protected: virtual void OnOK(); };
CMyDlgクラスではエジットコントロールから取得する 文字を格納するm_MyStrをpublicに宣言していることに注意してください。
ここは、いつもと変わらないです。// dlg01.cpp #include <afxwin.h> #include "dlg01.h" #include "resource.h" CMyApp myApp; BOOL CMyApp::InitInstance() { m_pMainWnd = new CMyWindow; m_pMainWnd->ShowWindow(m_nCmdShow); m_pMainWnd->UpdateWindow(); return TRUE; }
OnPaintハンドラが呼ばれたら、クライアント領域に MyMainStrを描画します。BEGIN_MESSAGE_MAP(CMyWindow, CFrameWnd) ON_WM_PAINT() ON_COMMAND(IDM_DLG, OnDlg) END_MESSAGE_MAP() CMyWindow::CMyWindow() { Create(NULL, "猫でもわかるダイアログボックス", WS_OVERLAPPEDWINDOW, rectDefault, NULL, "MYMENU"); } void CMyWindow::OnPaint() { CPaintDC dc(this); dc.TextOut(0, 0, MyMainStr); } void CMyWindow::OnDlg() { CMyDlg dlg(this); if(dlg.DoModal() == IDOK) { MyMainStr = dlg.m_MyStr; Invalidate(); } }
OnDlgハンドラが呼ばれたら(メニューから「ダイアログボックス」 が選択された)、ダイアログボックスを起動します。 戻り値がIDOKならdlg.m_MyStrをMyMainStrにコピーします。 そして、クライアント領域を再描画します。
メッセージボックスでOKボタンが押されたときの処理です。 メッセージマップがないことに注意してください。 また、最後にCDialog::OnOk();を呼びだしている点も注意してください。void CMyDlg::OnOK() { GetDlgItemText(IDC_EDIT1, m_MyStr); CDialog::OnOK(); }
CString& rStringに注意してください。C言語になれている人には ちょっととまどうかもしれませんが、参照です。 C++編第6章を見てください。CWnd::GetDlgItemText int GetDlgItemText( int nID, LPTSTR lpStr, int nMaxCount ) const; int GetDlgItemText( int nID, CString& rString ) const;
ダイアログボックスから文字列を取得して、これを親に渡すのが 簡単そうで難しいですね。もっと簡単にはグローバル変数を使うという 手があります。いろいろ試してみてください。
Update 13/Apr/1998 By Y.Kumei