■ MFC アプリケーションの作成 ■ ■ 初めに
此処では、Visual Studio 2017 を起動し、新しいプロジェクトで、MFC を選択し、MFC(Micorosft Foundation Class)アプリケーションを作成する。 ■ インストール時の注意 インストール時に、「ワークロード」で「C++によるデスクトップ開発」を選択した丈では、MFC アプ リケーションの開発を行う事が出来ない。右欄の「概要」で「x86 用と x64 用の Visual C++ MFC」に チェックを付ける必要が有る。亦、「個別のコンポーネント」で「x86 用と x64 用の Visual C++ MFC」 にチェックが入って居る事を確認する。 亦、CLR アプリケーションを開発する場合は、「概要」で「x86 用と x64 用の Visual C++ ATL」と「個 別のコンポーネント」で「C++/CLI サポート」にもチェックを入れて置く。 猶、此等は、「新しいプロジェクト」ダイアログで「Visual Studio インストーラを開く」から、何時で も追加する事が出来る。 ※ .NET Framework 登場に依り、現在では MFC を使っての新規開発は無いと思われるが、古いアプ リケーションの流用や保守の為に、一通りの使用法は憶えて置いた方が良いと思われる。
M
MF
FC
C
ア
アプ
プリ
リケ
ケー
ーシ
ショ
ョン
ン
■ シングルドキュメントの作成 ■ 新しいプロジェクトで MFC アプリケーションを選択すると、アプリケーションの種類のオプションの ダイアログが開くので、アプリケーションの種類にシングルドキュメントを選択して、次へボタンをク リックする。 ※ CView を使用する場合は、此処で完了ボタンをクリックしても構わないが、最低限不要なフレーム ペインを取り除く時や、ドキュメントビュー、エディットビュー、リストビュー、ツリービュー、 フォームビューを使用する時は、次へボタンをクリックしてウィザードを続ける。 アプリケーションの種類で選択する事が出来るのは、下記の通りで有る。 アプリケーションの種類 解説 シングルドキュメント メニューバー、ツールバー、ステータスバーを含む単一ウィンド ウのアプリケーション 複数のドキュメント メニューバー、ツールバー、ステータスバーを含むフレームウィ ンドウに複数の子ウィンドウを表示するのアプリケーション ダイアログベース 1個のダイアログを持つアプリケーション 複数のトップレベルドキュメント Visual Studio 風のアプリケーション
次のドキュメントテンプレートプロパティやユーザーインターフェース機能のダイアログでは何もせ ずに、次へをクリックする。 次の高度な機能オプションのダイアログの高度なフレームペインのチェックを総て外して、次へをクリ ックする。 最後の生成されたクラスのダイアログの基本クラスのドロップダウンリストで CFormView を選択して 完了ボタンをクリックする。 ※ アップデートの種類に依り、ダイアログの出現順序が異なる場合が有る。
プロジェクトが作成されると、ソリューションエクスプローラに下図の様なツリーが表示される。 リソースビューに切り替えて、IDD_MFCAPPLICATIONSDI_FORM をダブルクリックするとデザイ ン画面が表示される(名称は、IDD_プロジェクト名_FORM)。 ※ ソリューションエクスプローラのペインにリ ソースビューのタブが表示されて居ない場合 は、メニューの「表示」から「その他のウィン ドウ」をポイントし「リソースビュー」をクリ ックすると表示される様に成る。
実行(デバッグの開始 F5)すれば、下図の様な画面が表示される(高度なフレームペインのチェック を総て外して居ない場合は、更に色々なペインが装備されて居るので確認して欲しい)。 此処では、起動時にエディットコントロールに文字列を設定し、ボタンをクリックすると文字列を取得 してメッセージボックスで表示するアプリケーションを作成する事にする。 ■ デザイン 此のフォームに左側のツールボックスから必要なコントロールを貼り付ける事で画面のデザインが可 能で有る(ダイアログベースと異なり、此の時点でエラーは発生しない)。 ※ 上図では、Caption プロパティ而巳変更して居る。
コントロールを CFormView に貼り付けると、リソースファイル(プロジェクト名.rc)の下記に示す部 分(IDD_プロジェクト名_FORM)にコードが追加される(下記はエディットコントロールを貼り付け た場合で、スターティックテキストは初期状態で配置されて居る物)。
IDD_MFCAPPLICATIONSDI_FORM DIALOGEX 0, 0, 320, 200 STYLE DS_SETFONT | WS_CHILD
FONT 12, "MS UI Gothic", 0, 0, 0x1 BEGIN
LTEXT "TODO:フォームのコントロールをここに配置してください。",IDC_STATIC,24,42,280,8 EDITTEXT IDC_EDIT1,106,99,57,18,ES_AUTOHSCROLL END 因みに、此の部分をメモ帳等のテキストエディタで書き換える事も出来る(例えば、上記コードの 3 行 目を、FONT 12, "メイリオ", 0, 0, 0x1 と書き換えれば、フォームのフォントがメイリオの 12pt に変化 する)。但し、統合開発環境外での変更は推奨される事ではない。 主要なコントロールを、下記に示す。 PUSHBUTTON ボタン CONTROL チェックボックス EDITTEXT エディットコントロール(テキストボックス) COMBOBOX コンボボックス LISTBOX リストボックス GROUPBOX グループボックス CONTROL ラジオボタン LTEXT スターティックテキスト(ラベル) CONTROL ピクチャー ■ イベントハンドラ プロパティ欄をイベント一覧に切り替えて、ボタンがクリックされた時のイベントハンドラをコードに 追加する(BN_CLICKED を選択し、右側の下向き矢印をクリックして表示したドロップダウンリスト で <Add> OnBnClickedButton1 をクリックする)。 コントロールを右クリックしてイ ベントハンドラの追加のウィザー ドを表示する事も出来る。
下図のコードが表示されるので、此処にボタンをクリックした時の処理を記述する(此のイベントハン ドラは、C プロジェクト名 View.cpp ファイルの末尾の追加される)。 ■ ドキュメント ドキュメントクのヘッダーファイル(プロジェクト名 View.h)と実装(プロジェクト名 Doc.cpp)は変 更せずに其の儘使用する。 ■ ビュー ビュークラスのヘッダーファイル(プロジェクト名 View.h)は変更せずに其の儘使用する。 ビュークラスの実装(プロジェクト名 View.cpp)に下記のコードを追加する(赤字の部分)。 // MFCApplicationSDIView.cpp : CMFCApplicationSDIView クラスの実装 // #include "stdafx.h" // SHARED_HANDLERS は、プレビュー、縮小版、および検索フィルター ハンドラーを… // そのプロジェクトとのドキュメント コードの共有を可能にします。 #ifndef SHARED_HANDLERS #include "MFCApplicationSDI.h" #endif #include "MFCApplicationSDIDoc.h" #include "MFCApplicationSDIView.h" #ifdef _DEBUG
#define new DEBUG_NEW #endif // CMFCApplicationSDIView IMPLEMENT_DYNCREATE(CMFCApplicationSDIView, CFormView) BEGIN_MESSAGE_MAP(CMFCApplicationSDIView, CFormView) // 標準印刷コマンド ON_COMMAND(ID_FILE_PRINT, &CFormView::OnFilePrint) ON_COMMAND(ID_FILE_PRINT_DIRECT, &CFormView::OnFilePrint) ON_COMMAND(ID_FILE_PRINT_PREVIEW, &CMFCApplicationSDIView::OnFilePrintPreview) ON_WM_CONTEXTMENU() ON_WM_RBUTTONUP() ON_BN_CLICKED(IDC_BUTTON1, &CMFCApplicationSDIView::OnBnClickedButton1) END_MESSAGE_MAP() // CMFCApplicationSDIView コンストラクション/デストラクション
CMFCApplicationSDIView::CMFCApplicationSDIView() : CFormView(IDD_MFCAPPLICATIONSDI_FORM) { // TODO: 構築コードをここに追加します。 } CMFCApplicationSDIView::~CMFCApplicationSDIView() { } void CMFCApplicationSDIView::DoDataExchange(CDataExchange* pDX) { CFormView::DoDataExchange(pDX); } BOOL CMFCApplicationSDIView::PreCreateWindow(CREATESTRUCT& cs) {
// TODO: この位置で CREATESTRUCT cs を修正して Window クラスまたはスタイルを // 修正してください。 return CFormView::PreCreateWindow(cs); } void CMFCApplicationSDIView::OnInitialUpdate() { CFormView::OnInitialUpdate(); GetParentFrame()->RecalcLayout(); ResizeParentToFit(); // エディットボックスに文字列を設定 CString s = _T("文字列を入力して下さい。"); ((CEdit*)GetDlgItem(IDC_EDIT1))->SetWindowText(s); } // CMFCApplicationSDIView の印刷 void CMFCApplicationSDIView::OnFilePrintPreview() { #ifndef SHARED_HANDLERS AFXPrintPreview(this); #endif }
BOOL CMFCApplicationSDIView::OnPreparePrinting(CPrintInfo* pInfo) {
// 既定の印刷準備
return DoPreparePrinting(pInfo); }
{
// TODO: 印刷前の特別な初期化処理を追加してください。 }
void CMFCApplicationSDIView::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/) {
// TODO: 印刷後の後処理を追加してください。 }
void CMFCApplicationSDIView::OnPrint(CDC* pDC, CPrintInfo* /*pInfo*/) {
// TODO: 印刷用のコードをここに追加してください。 }
void CMFCApplicationSDIView::OnRButtonUp(UINT /* nFlags */, CPoint point) {
ClientToScreen(&point); OnContextMenu(this, point); }
void CMFCApplicationSDIView::OnContextMenu(CWnd* /* pWnd */, CPoint point) {
#ifndef SHARED_HANDLERS
theApp.GetContextMenuManager()->ShowPopupMenu(IDR_POPUP_EDIT, point.x, point.y, this, TRUE);
#endif }
// CMFCApplicationSDIView の診断 #ifdef _DEBUG
void CMFCApplicationSDIView::AssertValid() const {
CFormView::AssertValid(); }
void CMFCApplicationSDIView::Dump(CDumpContext& dc) const {
CFormView::Dump(dc); }
CMFCApplicationSDIDoc* CMFCApplicationSDIView::GetDocument() const // デバッグ以外のバ ージョンはインラインです。 { ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CMFCApplicationSDIDoc))); return (CMFCApplicationSDIDoc*)m_pDocument; } #endif //_DEBUG // CMFCApplicationSDIView メッセージ ハンドラー
void CMFCApplicationSDIView::OnBnClickedButton1() { // TODO: ここにコントロール通知ハンドラー コードを追加します。 CString s; ((CEdit*)GetDlgItem(IDC_EDIT1))->GetWindowText(s); MessageBox(s); } ■ MFC SDI の起動時の初期化の順番 起動時の初期化の順番は、下記の通りで有る(MFC の SDI 限定だが、MDI も然程違いは無い)。 順番 関数 解説 ① CxxxApp::CxxxApp() CxxxApp のコンストラクタ ② CxxxApp::InitInstance() start CxxxApp の初期化処理を開始 ③ CxxxDoc::CxxxDoc() ドキュメントのコンストラクタ ④ CMainFrame::CMainFrame() CMainFrame のコンストラクタ ⑤ CMainFrame::PreCreateWindow() CMainFrame のウィンド生成前の処理 ⑥ CMainFrame::OnCreate() start CMainFrame のウィンド生成処理を開始 ⑦ CxxxView::CxxxView() ビューのコンストラクタ
⑧ CxxxView::PreCreateWindow() ビューのウィンド生成前の処理
⑨ CMainFrame::OnCreate() end CMainFrame のウィンド生成処理を終了 ⑩ CxxxDoc::OnNewDocument() ドキュメントの新規作成処理
⑪ CxxxView::OnInitialUpdate() ビューの新規作成処理
⑫ CxxxApp::InitInstance() end CxxxApp の初期化処理を終了
上記の CxxxDoc::OnNewDocument 関数と CxxxView::OnInitialUpdate 関数に関しては、ドキュメン トの新規作成を行う度に呼び出されるので、普通の初期化処理を記述する事は出来ない。 猶、CxxxView::OnInitialUpdate 関数は、ビューがドキュメントに最初にアタッチされた後、ビューが 最初に表示される前に、フレームワークに依り呼び出されるので、此処に、ビューの初期化処理を記述 する。其の後、UpdateData 関数を呼んで表示を更新する。 ■ メンバ変数の追加 エディットコントロールのポインタは、((CEdit*)GetDlgItem(エディットコントロールの ID)) で取得 する事が出来る。 エディットコントロールに文字列を設定する時は、下記の様に SetDlgItemText 関数を使用する。 CString s = _T("文字列を入力して下さい。"); ((CEdit*)GetDlgItem(IDC_EDIT1))->SetWindowText(s); エディットコントロールから文字列を取得する時は、下記の様に GetDlgItemText 関数を使用する。 CString s; ((CEdit*)GetDlgItem(IDC_EDIT1))->GetWindowText(s); ※ 上記では、エディットボックスの ID を IDC_EDIT1 として居る。 但し、頻繁に使用する場合は、此の方法でポインタを取得するのは面倒なので、コントロール変数と謂 う便利な物が有る。
先ず、エディットコントロールを右クリックして、変数の追加を選択する。 次に、コントロール変数の追加ダイアログが表示 されるので、変数名(此処では m_edit)を入力 して、完了ボタンをクリックする。 ※ アクセス(スコープ)は、余程の事情が無い 限り public ではなく private に変更して置く 方が良い。
以上で、コントロール変数名.命令(此処では m_edit.命令)で簡単にエディットコントロールを制御す る事が出来る。 文字を読み取る場合や書き出す場合は、下記の様に記述する事が出来る。 CString s; m_edit.GetWindowTextA(s); // 取得 m_edit.SetWindowTextA(s); // 設定 因みに、整数値や実数値に変換する場合は、下記の様に記述する事が出来る。 int x = _ttoi( s.GetBuffer(0) );
double nBuf = atof(s.GetBuffer(0)); strDword.ReleaseBuffer(); ※ 猶、デザイン画面で Ctrl キーを押し乍らコントロールをダブルクリックしても、コントロール変数 の追加ダイアログを表示する事が出来る。 ■ ウィンドウスタイル 既定では、メインフォームのサイズは固定だが、ウィンドウスタイルを変更する事に依り、フォームの 枠線をドラッグしてサイズを変更する事が出来る様に成る。 此 等 の 設 定 は 、 MainFrm.cpp の PreCreateWindow 関 数 で 行 う 。 既 定 の の ス タ イ ル に 、 WS_THICKFRAME(又は WS_SIZEBOX)を追加する事で、フォームの枠線をドラッグしてサイズを 変更する事が出来る様に成る。 下記に、フォームの枠線をドラッグしてサイズを変更する事が出来る様にするコードを示す(赤字の部 分)。 BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs) { if( !CFrameWndEx::PreCreateWindow(cs) ) return FALSE;
// TODO: この位置で CREATESTRUCT cs を修正して Window クラスまたはスタイルを // 修正してください。
cs.style = WS_OVERLAPPED | WS_CAPTION | FWS_ADDTOTITLE
| WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_SYSMENU | WS_THICKFRAME;
return TRUE; }