MFCを始めようとしてみた

      暁 紫電




    わんくま同盟 東京勉強会 #78
自己紹介

• HN:暁 紫電
• 本名: 伊藤 伸男
• 職業: フリーランス・プログラ
  マー
  使用言語
   C++
   C++/CLI
   C#


     わんくま同盟 東京勉強会 #78
本日のアジェンダ

•   MFCとは?
•   なんでいまさらMFC
•   MFCの利点/欠点
•   とりあえずプロジェクトを作ってみる
•   ダイアログベース
•   まとめ




          わんくま同盟 東京勉強会 #78
MFCとは

• マイクロソフトがWindows アプリ作成
  用の
  フレームワークとして開発したライブ
  ラリ。

• 環境としては、「Visual C++ 1.0」の前
  の
  「C/C++ Compiler 7.0」から付属してい
  る。       わんくま同盟 東京勉強会 #78
なんでいまどきMFC?



• ロジックだけじゃなくてUIもC++で書
  きたい。

• 受けれる仕事の幅を増やしたい。




       わんくま同盟 東京勉強会 #78
MFC(というよりネイティブGUI)の利点

• .NET バージョンやラッパーの用意されて
  いないネイティブライブラリを低コストで
  呼び出すことが出来る。
• ネイティブなので速いはず。
• 実行時にネイティブに変換されるから速度
  は変わらないという話もあるが、
  すくなくても ネイティブへの変換コスト
  が掛からないはず。(JITコンパイル?)


         わんくま同盟 東京勉強会 #78
MFCの欠点

• MSDNに初心者向けチュートリアルがな
  い
 – MFC自体をある程度使える前提で
   新し目の機能(リボンインターフェースなど)に
   対応というようなチュートリアルはある
 – 初心者向けに0から作るようなチュートリアル
   がない。
 – 各技術項目を読んで理解する必要がある。



        わんくま同盟 東京勉強会 #78
MFCの欠点

• リファレンスもない。
パブリック クラス メンバーおよびプロテクト ク
ラス
メンバーは、アプリケーション プログラムや派生
クラスでよく使われるものだけを取り上げていま
す。 全クラス メンバーの一覧は、クラスのヘッ
ダー ファイルを参照してください。

http://msdn.microsoft.com/ja-jp/library/d06h2x6e.aspx
                   ソース読め
                     わんくま同盟 東京勉強会 #78
MFCの欠点(by wikipedia)

• CDocument, CView 等の基本的なクラスの
  仕様が難解である。
• Windowsメッセージ、コマンド等の
  Win32 APIの基本を理解していることが前
  提。
• すべての構造体、クラスおよび列挙型など
  がグローバル名前空間に存在している。
• マクロが多用されているため、識別子の衝
  突、競合が発生しやすい。

           わんくま同盟 東京勉強会 #78
MFCの欠点(by wikipedia)

• MFCが作られたのがC++の標準化以前であ
  るため、例外処理、実行時型情報などの
  機能がマクロを使用した独自実装となって
  いるため、標準C++に慣れたユーザーは戸
  惑う




         わんくま同盟 東京勉強会 #78
最初から生のWinAPIにしておけば良かった
        (´・ω・`)




       わんくま同盟 東京勉強会 #78
でもセッションもう頼まれちゃったしがんば
         る。
       (`・ω・´)




       わんくま同盟 東京勉強会 #78
とりあえずデフォルト設定で
 プロジェクトを作ってみる




    わんくま同盟 東京勉強会 #78
プロジェクトテンプレートから
MFCアプリケーションを選択




    わんくま同盟 東京勉強会 #78
わんくま同盟 東京勉強会 #78
わんくま同盟 東京勉強会 #78
わんくま同盟 東京勉強会 #78
わんくま同盟 東京勉強会 #78
わんくま同盟 東京勉強会 #78
わんくま同盟 東京勉強会 #78
わんくま同盟 東京勉強会 #78
わんくま同盟 東京勉強会 #78
設定項目が多すぎて
    なにやら
ありがた迷惑臭が漂います


    わんくま同盟 東京勉強会 #78
デフォルトプロジェクト 設定

• アプリケーションの種類:マルチドキュメ
  ント
• ドキュメント/ビューアーキテクチャー
• プロジェクト形式:VisualStudio
• Visual スタイルと色:Visual Studio 2008




            わんくま同盟 東京勉強会 #78
プロジェクトを作った状態




  わんくま同盟 東京勉強会 #78
デフォルトプロジェクト



•   デザイナが開いていない
•   .cppファイル 11個
•   .hファイル 13個
•   リソースファイル 27個




          わんくま同盟 東京勉強会 #78
デフォルト設定にしては大き過ぎない
        か?
    と思いつつコンパイル




      わんくま同盟 東京勉強会 #78
なにやらVisual Studio的なものが完成




        わんくま同盟 東京勉強会 #78
とりあえず
もう少しシンプルなものが作りた
       い




     わんくま同盟 東京勉強会 #78
とりあえず、最初の画面だけ
シンプルなそうな設定にしてみ
      る。




    わんくま同盟 東京勉強会 #78
わんくま同盟 東京勉強会 #78
シンプル?プロジェクト 設定

• アプリケーションの種類:シングルドキュ
  メント
• ドキュメント/ビューアーキテクチャー
• プロジェクト形式:MFC標準
• Visual スタイルと色:Windowsネイティブ/
  既定




          わんくま同盟 東京勉強会 #78
シンプルプロジェクト



•   相変わらずデザイナなし
•   .cppファイル 5個
•   .hファイル 7個
•   リソースファイル 7個




          わんくま同盟 東京勉強会 #78
だいぶシンプルになったけど




  わんくま同盟 東京勉強会 #78
それでも色々付いてます。




  わんくま同盟 東京勉強会 #78
デザイナなし・まとめ

• ウィザードの最初の画面をいじるだけだと
  最小限のものは作れない。
• 本当に最小限のプロジェクトを作ろうとす
  ると
  めんどくさそう
• そもそも最小限の状態から作り始めるもの
  じゃないかもしれない。
• ウィザードで雛形を作ってそれを元にして
  アプリケーションを作っていくべき?

       わんくま同盟 東京勉強会 #78
デフォルト設定じゃないけど
ちゃんとデザイナもあります。




    わんくま同盟 東京勉強会 #78
わんくま同盟 東京勉強会 #78
デザイナはリソースビューから選択可能




     わんくま同盟 東京勉強会 #78
今回は割とシンプルなものが出来上がります




      わんくま同盟 東京勉強会 #78
最初からボタンが2つ




      クリックするとダイアログが
      閉じアプリケーションが終了
      します。
      DialogResult的な物

 わんくま同盟 東京勉強会 #78
最初からボタンが2つ




開発時にダブルクリックすると、
OnBnClickedOK(),OnBnClickedCancel()が作られる。
内部で OnOK(), OnCancel();を呼び出している



          わんくま同盟 東京勉強会 #78
ダイアログが勝手に閉じないようにする。

• とりあえずコントロールを削除してみる
• 削除してもEnter/Escを押せば閉じてしまう。
• OnBnClickedOk()/Cancel()で呼び出されている
  CDialogEx::OnOK()/OnCancel()を削除すれば
  キーを押しても閉じなくなる。
void CDialog1Dlg::OnBnClickedOk()
{
     // TODO: ここにコントロール通知ハンドラー コードを追加します。
     CDialogEx::OnOK(); ←コレを消す
}




              わんくま同盟 東京勉強会 #78
ダイアログが勝手に閉じないようにする。(Cancel)

• OnCancel()の呼び出しを消してしまうと
  Escボタンだけじゃなくて閉じるボタンや
  Alt+F4でもウィンドウが閉じられなくなっ
  てしまう

※(ウィンドウを閉じようとすると
OnBnClickedCancel()が呼び出され、その中で閉じ
る処理( OnCancel() )が行われるため



           わんくま同盟 東京勉強会 #78
Escキーでダイアログが閉じないようにする。

Escでは閉じず他の手段では閉じるようにするためには、
PreTranslateMessageをオーバーライドする必要がある。
BOOL CDialog1Dlg::PreTranslateMessage(MSG* pMsg)
{
      if( WM_KEYDOWN == pMsg->message )
      {
              if(pMsg->wParam == VK_ESCAPE)
              { return FALSE; }
      }
      return CDialogEx::PreTranslateMessage(pMsg);
}



                       わんくま同盟 東京勉強会 #78
MFCの正しい使い方?
• デザイナなし(Doc-View等)でアプリ本体を
  作って設定ダイアログ等をダイアログベー
  スで作るのがMFCの正しい使い方っぽ
  い?

• アプリの内容にもよるがダイアログベース
  で全部作ってしまう事のほうが
  多そうな気も……


         わんくま同盟 東京勉強会 #78
とりあえずなんか作る

• ボタンをクリックするとテキストボックス
  の中身がメッセージダイアログで表示され
  る
• ダイアログボックスを閉じるとテキストコ
  ントロールにそのテキストボックスの中身
  を表示する。
• WinFormsであればコントロールに対応す
  る変数を操作すればすぐ出来る簡単なアプ
  リ

        わんくま同盟 東京勉強会 #78
とりあえず、コントロールを配置




   わんくま同盟 東京勉強会 #78
コントロールに対応した変数が作られていない。
// CDialog1Dlg ダイアログ
class CDialog1Dlg : public CDialogEx
{
     // ~略~
public:
     afx_msg void OnBnClickedOk();
     afx_msg void OnBnClickedCancel();

     virtual BOOL PreTranslateMessage(MSG* pMsg);
     afx_msg void OnBnClickedButton1();


};


                   わんくま同盟 東京勉強会 #78
コントロールを選択して右クリック→変数の追加




       わんくま同盟 東京勉強会 #78
変数のカテゴリ

• Value
    主に表示している文字列に対応した変
数
    int,CString等

• Control
    配置したコントロールに対応したクラ
ス
    CStatic,CButton,CEdit等
         わんくま同盟 東京勉強会 #78
変数の追加結果
// CDialog1Dlg ダイアログ
class CDialog1Dlg : public CDialogEx
{
     // ~略~
public:
     afx_msg void OnBnClickedOk();
     afx_msg void OnBnClickedCancel();

     virtual BOOL PreTranslateMessage(MSG* pMsg);
     afx_msg void OnBnClickedButton1();

     CEdit TextBox1;      //テキストボックスに対応したControll変数
     CString LabelText; //ラベルの文字列に対応したValue変数

};

                      わんくま同盟 東京勉強会 #78
DDX/DDV

• 変数を追加するとDoDataExchange()に
  DDX/DDV系関数の呼び出しが追加される。
void CDialog1Dlg::DoDataExchange(CDataExchange*
pDX)
{
     CDialogEx::DoDataExchange(pDX);

    DDX_Control(pDX, IDC_EDIT1, TextBox1);
    DDX_Text(pDX, IDC_RESULT, LabelText);
    DDV_MaxChars(pDX, LabelText, 10);
}


                  わんくま同盟 東京勉強会 #78
DDX/DDV

• DDX: Dialog Data eXchange
  変数の内容を実際のコントロールに反
映、
  コントロールの内容を変数に反映させ
る。

• DDV: Dialog data validation
  データの妥当性検査

               わんくま同盟 東京勉強会 #78
DoDataExchange(CDataExchange* pDX)
• pDxのメンバーm_bSaveAndValidateがTRUEの
  場合
  コントロールの内容を変数に反映する

• FALSEの場合
  変数の内容をコントロールに転送する。

• CWnd::UpdateData(BOOL)で呼び出すことが出
  来る。


              わんくま同盟 東京勉強会 #78
なんとなくMVC系でいう
中間層的な動作をしている気がす
       る。

※厳密な意味ではないので適当に聞き流して下さい



       わんくま同盟 東京勉強会 #78
OnBnClickedButton1()
void CDialog1Dlg::OnBnClickedButton1()
{
     CString str;  //文字列変数の作成

    //テキストボックスの文字列を取得
    TextBox1.GetWindowTextW(str);

    // メッセージボックに表示
    AfxMessageBox(str,IDOK);

    // ラベルの文字列を更新
    this->LabelText = str;

    UpdateData(FALSE);    // 反映
}

                     わんくま同盟 東京勉強会 #78
問題点

• 追加した変数すべてのDDX/DDVが
  DoDataExchange()に含まれるので
  ひとつの変数に関してだけ更新したいとき
  でもすべての変数に対して更新されてしま
  う。
• 変数が多くなると、更新したいわけではな
  い変数に対する処理のせいで
  動作が重くなる可能性がある。


         わんくま同盟 東京勉強会 #78
CWnd::GetDlgItem(int nID )
• CWnd::GetDlgItemを用いることで、
  DoDataExChange()を使わずに、コント
  ロールと関連付けられた変数へのポインタ
  を取得できる。
void CDialog1Dlg::OnBnClickedButton1()
{
     CEdit* pTextBox = (CEdit*)this->GetDlgItem(IDC_EDIT1);
     CStatic* pLabel = (CStatic*)this->GetDlgItem(IDC_LABEL);

    CString str;
    pTextBox->GetWindowTextW(str);
    AfxMessageBox(str,IDOK);
    pLabel->SetWindowTextW(str);
}

                        わんくま同盟 東京勉強会 #78
ダイアログベース・まとめ

• 基本的には設定ダイアログ等を作るためのも
  の
• アプリ自体の作成に使うなら、必要に応じて
  OnOK OnCancelが呼び出されないように修
  正。
• 変数の追加、
  DDX/DDV関数でコントロールを操作する。

• DoDataExChange()の肥大化が気になる場合
  はGetDlgItem()でコントロール対応クラスへ
  のポインタを取得     わんくま同盟 東京勉強会 #78
最後に

• ありがた迷惑設計だけど慣れればどうにか
  なりそう

• でも本格的に使うならフレームワーク的な
  ものを作ったほうがいいかもしれない

• でもそれって自分でWinAPIを自分でラッ
  プして使うのとあまり変わりないのでは?


        わんくま同盟 東京勉強会 #78

わんくまT78 mfcを始めようとしてみた