第12章 もう少し複雑なダイアログボックス


今回はラジオボタンなどを持つもう少し複雑なダイアログボックス を作ります。基本的には前回と全く同じです。

その前にダイアログボックスとメインウィンドウとのデータのやりとり をまとめてみます。

1.自作ダイアログボックスクラスにpublicなデータ用メンバを持たせる   CMyDlg(CWnd *pParentWnd = NULL) : CDialog("MYDLG", pParentWnd) {}   のようにコンストラクタを定義しておくと後が楽 2.メインのウィンドウクラスにprivateなデータ用メンバを持たせる 3.メインウィンドウ側から CMyDlg dlg(this);   dlg.DoModal(); でダイアログボックスを呼び出す 4.DoModal();の戻り値がIDOKならダイアログボックスのデータを   メインウィンドウのデータにコピー 5.ダイアログボックス側でOnOK関数をオーバーライドする   ダイアログボックスのコントロールよりデータを取得   オーバーライドしたときは本来のOnOK関数を実行 6.メインウィンドウ側で必要な処理を行う

実際に4は5の後で行われます。ちょっと回りくどい方法です。 が、今回もこの方法に則ってやります。


親ウィンドウのクライアント領域を左クリックすると 左のようなダイアログボックスが出現します。 性別は「男」「女」「不明」のいずれか1つしか選択できません。 (ラジオボタン)

一方ペットは複数を選択できます。(全く選択しなくてもよい)


ダイアログボックスに適当な入力を行ってOKボタンを押すと 親ウィンドウにその内容が描画されます。


今回必要になってくる関数は

CString::Format void Format( LPCTSTR lpszFormat、 ... ); void Format( UINT nFormatID、 ... );

C言語になれている人はついwsprintfを使ってしまいがちですが CStringクラスにはこのような便利な関数がついています。

lpszFormatに書式制御文字列を指定します。または書式制御 文字列を含むリソースの識別子を指定します。 使い方はwsprintfと同じです。

CWnd::GetCheckedRadioButton int GetCheckedRadioButton( int nIDFirstButton, int nIDLastButton );

チェックされているラジオボタンのIDを返します。
nIDFirstButtonはグループ内の最初のボタンのID、 nIDLastButtonは最後のボタンのIDです。

CWnd::IsDlgButtonChecked UINT IsDlgButtonChecked( int nIDButton ) const;

nIDButtonで指定されたボタンがチェックされているかどうかを 調べます。チェックされていないと0を、チェックされていると 0以外の値を返します。

では、プログラムを見てみましょう。

// dlg02.rcの一部 ///////////////////////////////////////////////////////////////////////////// // // Dialog // MYDLG DIALOG DISCARDABLE 0, 0, 123, 147 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "入力ボックス" FONT 9, "MS Pゴシック" BEGIN DEFPUSHBUTTON "OK",IDOK,7,126,50,14 PUSHBUTTON "キャンセル",IDCANCEL,63,126,50,14 EDITTEXT IDC_EDIT1,26,7,65,15,ES_AUTOHSCROLL LTEXT "氏名:",IDC_STATIC,7,13,18,8 LTEXT "年齢:",IDC_STATIC,7,31,18,8 EDITTEXT IDC_EDIT2,26,27,65,15,ES_AUTOHSCROLL GROUPBOX "性別",IDC_STATIC,7,55,109,32 CONTROL "男",IDC_RADIO1,"Button",BS_AUTORADIOBUTTON,14,70,23,10 CONTROL "女",IDC_RADIO2,"Button",BS_AUTORADIOBUTTON,45,70,23,10 CONTROL "不明",IDC_RADIO3,"Button",BS_AUTORADIOBUTTON,76,70,30, 10 GROUPBOX "ペット",IDC_STATIC,7,93,109,28 CONTROL "犬",IDC_CHECK1,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7, 105,23,10 CONTROL "猫",IDC_CHECK2,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,43, 105,23,10 CONTROL "その他",IDC_CHECK3,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,79,105,36,10 END

これは、普通のダイアログボックスのリソーススクリプトです。

// dlg02.h class CMyApp : public CWinApp { public: virtual BOOL InitInstance(); }; class CMyWindow : public CFrameWnd { private: CString m_MyTxt1; CString m_MyTxt2; int m_Seibetsu; int m_Pet[3]; public: CMyWindow(); protected: afx_msg void OnPaint(); afx_msg void OnClose(); afx_msg void OnLButtonDown(UINT, CPoint); DECLARE_MESSAGE_MAP() }; class CMyDlg : public CDialog { public: CMyDlg(CWnd* pParentWnd = NULL) : CDialog("MYDLG", pParentWnd){}; CString m_name; CString m_age; int m_Sex; UINT m_Pets[3]; protected: virtual void OnOK(); };

ヘッダーファイルです。CMyDlgクラスではOnOK()しか 処理しないのでDECLARE_MESSAGE_MAP()は不要です。

// dlg02.cpp #include <afxwin.h> #include "dlg02.h" #include "resource.h" CMyApp myApp; BOOL CMyApp::InitInstance() { m_pMainWnd = new CMyWindow; m_pMainWnd->ShowWindow(m_nCmdShow); m_pMainWnd->UpdateWindow(); return TRUE; }

これは、いつもと同じです。

BEGIN_MESSAGE_MAP(CMyWindow, CFrameWnd) ON_WM_PAINT() ON_WM_CLOSE() ON_WM_LBUTTONDOWN() END_MESSAGE_MAP() CMyWindow::CMyWindow() { Create(NULL, "猫でもわかるダイアログボックス"); } void CMyWindow::OnPaint() { CPaintDC dc(this); CString string, sei, pet; string.Format("氏名=%s", (LPCTSTR)m_MyTxt1); dc.TextOut(10, 10, string); string.Format("年齢=%s", (LPCTSTR)m_MyTxt2); dc.TextOut(10, 40, string); switch (m_Seibetsu) { case IDC_RADIO1: sei = "男"; break; case IDC_RADIO2: sei = "女"; break; case IDC_RADIO3: sei = "不明"; break; } string.Format("性別=%s", sei); dc.TextOut(10, 70, string); if (m_Pet[0]) pet += "犬 "; if (m_Pet[1]) pet += "猫 "; if (m_Pet[2]) pet += "その他"; string.Format("ペット=%s", (LPCTSTR)pet); dc.TextOut(10, 100, string); } void CMyWindow::OnLButtonDown(UINT nFlags, CPoint pt) { int i; CMyDlg dlg(this); if(dlg.DoModal() == IDOK) { m_MyTxt1 = dlg.m_name; m_MyTxt2 = dlg.m_age; m_Seibetsu = dlg.m_Sex; for (i = 0; i <= 2; i++) m_Pet[i] = dlg.m_Pets[i]; Invalidate(); } } void CMyWindow::OnClose() { int id; id = MessageBox("終了してもよいですか", "終了確認", MB_ICONQUESTION | MB_OKCANCEL); if (id == IDOK) CWnd::OnClose(); }

CMyWindowのOnPaint()でCStringクラスのオブジェクトに「+=」という 演算子を使っていることに注意してください。これは、C言語で 数値にたいして「+=」という演算子を使いますが雰囲気は全く同じです。

CString Mystr = "粂井";
Mystr += "康孝";

とするとMystrは"粂井康孝"となります。

OnLButtonDown()でダイアログボックスを呼んでいます。 また、DoModalの戻り値がIDOKの時(ダイアログボックスでOKボタンが押されたとき) 自分のデータメンバにダイアログボックスのデータメンバをコピーしています。

さらに、今回はWM_CLOSEメッセージも処理しています。 アプリケーションが終了しようとしている時(左上の×印が押された、システムメニューの「閉じる」 が選択されたときなど)本当に終了してよいかを尋ねるメッセージボックスを出しています。 これがIDOKの時は本来のOnClose関数を呼んで、ウィンドウを終了させます。 もしくはDestroyWindow()関数を呼んでも同じです。

void CMyDlg::OnOK() { GetDlgItemText(IDC_EDIT1, m_name); GetDlgItemText(IDC_EDIT2, m_age); m_Sex = GetCheckedRadioButton(IDC_RADIO1, IDC_RADIO3); m_Pets[0] = IsDlgButtonChecked(IDC_CHECK1); m_Pets[1] = IsDlgButtonChecked(IDC_CHECK2); m_Pets[2] = IsDlgButtonChecked(IDC_CHECK3); CDialog::OnOK(); }

ダイアログボックスでOKボタンが押されたときの処理です。 各コントロールの値を自分のデータメンバに書き込んでいます。 OnOK関数はオーバーライドしているので、最後に本来のCDialog::OnOK() 関数を呼ばないといつまでもダイアログボックスが閉じません。
[MFC Index] [総合Index] [Previous Chapter] [Next Chapter]

Update 06/May/1998 By Y.Kumei
当ホーム・ページの一部または全部を無断で複写、複製、 転載あるいはコンピュータ等のファイルに保存することを禁じます。