MFC アプリケーション 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 を使っての新規開発は無いと思われるが 古いアプリケーションの流用や保守の為に 一通りの使用法は憶えて置いた方が良いと思われる -1-
シングルドキュメントの作成 新しいプロジェクトで MFC アプリケーションを選択すると アプリケーションの種類のオプションのダイアログが開くので アプリケーションの種類にシングルドキュメントを選択して 次へボタンをクリックする ( 此処で完了ボタンをクリックしても構わないが 不要なフレームペインを取り除く為 次へボタンをクリックしてウィザードを続ける ) 次のドキュメントテンプレートプロパティやユーザーインターフェース機能のダイアログでは何もせずに 次へをクリックする 次の高度な機能オプションのダイアログの高度なフレームペインのチェックを総て外して 完了をクリックする アップデートの種類に依り ダイアログの出現順序が異なる場合が有る アプリケーションの種類解説シングルドキュメントメニューバー ツールバー ステータスバーを含む単一ウィンドウのアプリケーション複数のドキュメントメニューバー ツールバー ステータスバーを含むフレームウィンドウに複数の子ウィンドウを表示するのアプリケーションダイアログベース 1 個のダイアログを持つアプリケーション複数のトップレベルドキュメント Visual Studio 風のアプリケーション -2-
プロジェクトが作成されると ソリューションエクスプローラに下図の様なツリーが表示される 上図のファイルを観ると解る様に プロジェクト名に Doc の付加されたファイルと View の付加されたファイルが存在する 此の様に ドキュメント ( データ ) と画面 ( ビュー ) を分けてアプリケーションを構築する方法を DOC/VIEW モデルと謂い 現在では一般的な手法で有る MFC ではドキュメントの基本クラスとして CDocument ビューの基本クラスとして CView と謂うクラスが用意されて居て 此等のクラスからアプリケーション独自のドキュメントとビュークラスを派生させてプログラムを構築する 猶 リソースビューに切り替えると アイコン等の色々なリソースを観る事が出来る ソリューションエクスプローラのペインにリソースビューのタブが表示されて居ない場合は メニューの 表示 から その他のウィンドウ をポイントし リソースビュー をクリックすると表示される様に成る -3-
実行 ( デバッグの開始 F5) すれば 下図の様な画面が表示される ( 高度なフレームペインのチェックを総て外して居ない場合は 更に色々なペインが装備されて居るので確認して欲しい ) 此処では 空気抵抗を受けるボールの運動形を描画するグラフィックアプリケーションを作成する事にする ドキュメント ドキュメントクラスのヘッダーファイル ( プロジェクト名 Doc.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" #include <math.h> -4-
#ifdef _DEBUG #define new DEBUG_NEW #endif // 変数の定義 #define g 9.8 #define PI 3.14159 #define d 0.072 #define dt 0.03 // 重力加速度 // 円周率 // ボールの直径 // 計算時間間隔 // 関数の宣言 double _sgn(double, int); // 符号変化の関数 void timewait(int); // 時間待 // CMFCApplicationSDIView IMPLEMENT_DYNCREATE(CMFCApplicationSDIView, CView) BEGIN_MESSAGE_MAP(CMFCApplicationSDIView, CView) // 標準印刷コマンド ON_COMMAND(ID_FILE_PRINT, &CView::OnFilePrint) ON_COMMAND(ID_FILE_PRINT_DIRECT, &CView::OnFilePrint) ON_COMMAND(ID_FILE_PRINT_PREVIEW, &CMFCApplicationSDIView::OnFilePrintPreview) ON_WM_CONTEXTMENU() ON_WM_RBUTTONUP() END_MESSAGE_MAP() // CMFCApplicationSDIView コンストラクション / デストラクション CMFCApplicationSDIView::CMFCApplicationSDIView() // TODO: 構築コードをここに追加します CMFCApplicationSDIView::~CMFCApplicationSDIView() BOOL CMFCApplicationSDIView::PreCreateWindow(CREATESTRUCT& cs) // TODO: この位置で CREATESTRUCT cs を修正して Window クラスまたはスタイルを // 修正してください return CView::PreCreateWindow(cs); // CMFCApplicationSDIView 描画 void CMFCApplicationSDIView::OnDraw(CDC* pdc) CMFCApplicationSDIDoc* pdoc = GetDocument(); ASSERT_VALID(pDoc); -5-
if (!pdoc) return; // TODO: この場所にネイティブデータ用の描画コードを追加します CPen pc1(ps_solid, 1, RGB(0, 125, 128)); // ペンの初期化 CPen pc3(ps_solid, 2, RGB(0, 0, 255)); CPen* oldp = pdc->selectobject(&pc1); // ペンの変更 int x0 = 50, y0 = 380, xsp = 600, ysp = 300; // 作図範囲 int xp, yp; int ss = 0; CString str; double xmax = 120, ymax = 50; // 各変数 double a, cd, l; double x, y, v0, vi0, t, th; double xd, yd, x2d, y2d, r, m; cd = 0.4; // 空気抵抗係数 l = 1.25 / g; // 空気密度 m = 0.146 / g; // ボールの質量 x = y = t = 0; vi0 = 150; // 初速度 th = 45; // 打ち上げ角度 v0 = vi0 * 1000.0 / 3600.0; th = th * PI / 180.0; a = d * d*pi / 4.0; xd = v0 * cos(th); yd = v0 * sin(th); // 軸の表示 pdc->selectobject(&pc3); pdc->moveto(x0, y0); pdc->lineto(x0 + xsp, y0); pdc->moveto(x0, y0); pdc->lineto(x0, y0 - ysp); str = " 空気抵抗を受けるボールの放物運動計算プログラム "; pdc->settextcolor(rgb(0, 0, 255)); pdc->textout(60, 0,str); // 文字出力 pdc->selectobject(&pc1); while (y >= 0) xp = (int)(x0 + x * xsp / xmax); yp = (int)(y0 - y * ysp / ymax); pdc->ellipse(xp - 3, yp - 3, xp + 3, yp + 3); // 左上と右下に接する楕円 r = 0.5*l*a*cd; // 運動方程式の解 ss = (int)_sgn(xd, ss); x2d = -r * (xd * xd) / m * ss; xd += x2d * dt; x += xd * dt; -6-
ss = (int)_sgn(yd, ss); y2d = -r * yd*yd / m * ss - g; yd += y2d * dt; y += yd * dt; t += dt; timewait(1000); // 時間待ち pdc->settextcolor(rgb(250, 52, 50)); str.format(_t(" 到達距離 = %f"), x); pdc->textout(120, 40, str); // 文字出力 pdc->selectobject(oldp); // ペンを元に戻す // CMFCApplicationSDIView の印刷 void CMFCApplicationSDIView::OnFilePrintPreview() #ifndef SHARED_HANDLERS AFXPrintPreview(this); #endif BOOL CMFCApplicationSDIView::OnPreparePrinting(CPrintInfo* pinfo) // 既定の印刷準備 return DoPreparePrinting(pInfo); void CMFCApplicationSDIView::OnBeginPrinting(CDC* /*pdc*/, CPrintInfo* /*pinfo*/) // TODO: 印刷前の特別な初期化処理を追加してください void CMFCApplicationSDIView::OnEndPrinting(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 -7-
// CMFCApplicationSDIView の診断 #ifdef _DEBUG void CMFCApplicationSDIView::AssertValid() const CView::AssertValid(); void CMFCApplicationSDIView::Dump(CDumpContext& dc) const CView::Dump(dc); CMFCApplicationSDIDoc* CMFCApplicationSDIView::GetDocument() const ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CMFCApplicationSDIDoc))); return (CMFCApplicationSDIDoc*)m_pDocument; #endif //_DEBUG // 記号変更 double _sgn(double dd, int s) if (dd < 0) s = -1; else if (dd == 0) s = 0; else s = 1; return(s); // 時間待 void timewait(int n) int a, i, j, m = 1000; for (i = 0; i<n; i++) for (j = 0; j<m; j++) a = i; // CMFCApplicationSDIView メッセージハンドラー -8-