第6章 メニュー


今回は、メニューを付けます。 作り方は簡単です。 VC++ではリソースエジタでメニューを作ります。 適当な名前(***.rc)で保存します。このファイルをプロジェクトに 参加させます。ソースファイルに#include "resource.h"します。 Create()関数のメニュー名の引数にメニュー名を記載します。 これで、少なくともメニューは表示されます。

では、ではメニューで選択された項目をどのようにして知ればよいのでしょうか。 SDKでは、WM_COMMANDメッセージの処理でした。WM_COMMANDメッセージを 捕まえて、この時のLOWORD(wParam)がシンボルでした。MFCでは メッセージマップエントリで行います。

ON_COMMAND(シンボル名、処理関数)

とします。関数名は何でもいいのですが、OnPaintとかOnChar関数のように Onで始まる名前にするのが一般的です。


メニューがついて少しWindowsのプログラムらしくなりました。 クライアント領域に表示されている文字はウィンドウの大きさを変えても ほぼ中央に来るようにしてみました。


では、早速プログラムの中身を見てみましょう。

// menu01.rcの一部です。 ////////////////////////////////////////////////////////////// // // Menu // MYMENU MENU DISCARDABLE BEGIN POPUP "ファイル(&F)" BEGIN MENUITEM "終了(&X)", IDM_END END POPUP "ヘルプ(&H)" BEGIN MENUITEM "About", IDM_ABOUT END END

普通のメニューリソースです。ここで定義したシンボルはIDM_ENDとIDM_ABOUTです。

// menu01.h class CMyApp : public CWinApp { public: virtual BOOL InitInstance(); }; class CMyWindow : public CFrameWnd { public: CMyWindow(); //コンストラクタ afx_msg void OnPaint(); afx_msg void OnEnd(); afx_msg void OnAbout(); DECLARE_MESSAGE_MAP() };

今回もクラス定義部分をヘッダーファイルに分離しました。 メニューから「終了」とか「About」などが選択されたときに呼ばれるのが OnEnd(), OnAbout()の自作関数です。

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

ソースファイルの最初の方です。シンボル定義ファイル"resource.h"の インクルードを忘れないでください。自作の"menu01.h"も忘れないでください。

BEGIN_MESSAGE_MAP(CMyWindow, CFrameWnd) ON_WM_PAINT() ON_COMMAND(IDM_END, OnEnd) ON_COMMAND(IDM_ABOUT, OnAbout) END_MESSAGE_MAP()

CMyWindowクラスのメッセージマップです。 メニューからIDM_ENDが選択されたらOnEnd()関数が呼ばれ、 IDM_ABOUTが選択されたら、OnAbout()関数が呼ばれます。

CMyWindow::CMyWindow() { Create(NULL, "猫でもわかるメニュー", WS_OVERLAPPEDWINDOW, CRect(100, 100, 100+220, 100+120), NULL, "MYMENU"); }

コンストラクタです。Create関数の6番目の引数にメニュー名を指定します。

void CMyWindow::OnPaint() { int y; RECT rc; TEXTMETRIC tm; CString str = "粂井康孝・制作"; CPaintDC dc(this); GetClientRect(&rc); dc.GetTextMetrics(&tm); dc.SetTextAlign(TA_CENTER); dc.SetTextColor(RGB(255, 0, 0)); y = (rc.bottom - tm.tmAscent) / 2; dc.TextOut(rc.right / 2, y, str); }

クライアント領域への描画ですが中央に表示するために 少し工夫しています。TextOut()関数の最初の2つの引数は 座標を表しますが、これは、デフォルトではフォントの左上の座標を指定することになります。 そこでSetTextAlign()関数により基準点を変えます。

CDC::SetTextAlign UINT SetTextAlign( UINT nFlags );

nFlagsで基準点を指定します。TA_CENTERは水平方向の中央、TA_LEFTは左端、TA_RIGHTは右端、 TA_BASELINEは垂直方向でフォントのベースライン、TA_BOTTOMは下端、TA_TOPは上端となります。 デフォルトはTA_TOP | TA_LEFTということになります。

クライアント領域の大きさはGetClientRect関数で調べます。

CWnd::GetClientRect void GetClientRect( LPRECT lpRect ) const;

lpRectはRECT構造体またはCRectオブジェクトへのポインタです。

フォントの大きさを知るためにGetTextMetrics()関数を使いました。

CDC::GetTextMetrics BOOL GetTextMetrics( LPTEXTMETRIC lpMetrics ) const;

lpMetricsはTEXTMETRIC構造体へのポインタです。この構造体の メンバは山ほどあってとても全部は解説できません。ここではtmAscentメンバを フォントの高さとして扱いました。クライアント領域の高さからフォントの高さを ひいて2で割るとフォントの左上のy座標をどこに持ってくれば良いかがわかります。 x座標についてはTA_CENTERを指定してクライアント領域の幅の半分にすれば 良いですね。

void CMyWindow::OnAbout() { MessageBox("粂井康孝・制作著作", "About"); }

メニューからIDM_ABOUTが選択されたとき実行される関数です。 単にメッセージボックスを出しているだけです。

CWnd::MessageBox int MessageBox( LPCTSTR lpszText, LPCTSTR lpszCaption = NULL, UINT nType = MB_OK );

SDKのメッセージボックスと同じ使い方です。ヘルプによると この関数よりAfxMessageBox()関数を推奨しています。

void CMyWindow::OnEnd() { SendMessage(WM_CLOSE); }

メニューからIDM_ENDが選択されたときに実行される関数です。 単にWM_CLOSEメッセージを送ってアプリケーションを終了させています。

CWnd::SendMessage LRESULT SendMessage( UINT message, WPARAM wParam = 0, LPARAM lParam = 0 );

wParamとlParamを省略すると0が代入されます。

さて、今回は簡単でした。新しいメンバ関数もいろいろ出てきましたが どれもAPI関数から使い方が類推されます。API関数の第一引数がない形が多いですね。 また、デフォルト引数も多く少しだけ楽ができます。


[MFC Index] [総合Index] [Previous Chapter] [Next Chapter]

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