1日でわかるMFC (GARAさんのページ)
BACK  
 Sample_C ボタンを持つWindowsプログラム

Sample_C1.c はSDKのプログラムです。
Sample_C2.cpp はメインウィンドウのみクラス化しています。
Sample_C3.cpp はメインウィンドウとボタンをクラス化しています。

プログラム概要
・ ボタンをクリックするとメッセージボックスを表示します。
・ 右側のボタンはサブクラス化(MFCのクラスとは別物)して独自の処理(右クリック処理)を追加しています。



共通ファイル
1)Sample_C.h
#define MENU_NAME   NULL        // メニュー名
#define WIN_W       500         // Window の幅
#define WIN_H       180         // Window の高
#define WIN_X       100         // Window の水平座標
#define WIN_Y       50          // Window の垂直座標
#define BTN_ID0     200         // ボタンID
#define BTN_ID1     201
#define BTN_ID2     202

 Sample_C1.c SDKのプログラム (緑色の部分は各 .c ファイル共通です)
TOP  
/** Sample_C1.c:ボタンを持つWindowsプログラム (by GARA) **/

#include <windows.h>
#include "Sample_C.h"

/* Define */
#define CLASS_NAME  "Sample_C1Class"    // クラス名
#define WIN_TITLE   "Sample_C1"         // タイトル

/* Global */
HINSTANCE   hInst;
HWND        hButton[3];
WNDPROC     BtnDefProc[3];

/* Proto Type */
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
BOOL InitApplication(HINSTANCE);
BOOL InitInstance(HINSTANCE, int);
void PutButton(HWND, int, int, int, int, int, char *);
void ClrButton(int);
LRESULT CALLBACK BtnProc_2(HWND, UINT, WPARAM, LPARAM);

/* WinMain */
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    Sample_A1.c と同じ
}

/* ウィンドウクラスの登録 */
BOOL InitApplication(HINSTANCE hInstance)
{
    Sample_A1.c と同じ
}

/* ウィンドウの作成と表示 */
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
    Sample_A1.c と同じ
}

/* ウィンドウプロシージャ */
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    HDC         hDC;
    PAINTSTRUCT ps;

    switch(uMsg) {
        case WM_CREATE:
            PutButton(hWnd, 1,  70, 100, 150, 30, "左クリックボタン");
            PutButton(hWnd, 2, 280, 100, 150, 30, "右クリックボタン");
            break;
        case WM_PAINT:
            BeginPaint(hWnd, &ps);
            hDC = ps.hdc;
            TextOut(hDC, 10, 10, "SDK -> MFC", 10);
            EndPaint(hWnd, &ps);
            break;
        case WM_COMMAND:    // ボタンか押された
            switch(LOWORD(wParam)) {
                case BTN_ID1:       // ボタン1
                    MessageBox(hWnd, "左側のボタンが押されました", "ボタン", MB_OK);
                    break;
                case BTN_ID2:       // ボタン2
                    MessageBox(hWnd, "右側のボタンが押されました", "ボタン", MB_OK);
                    break;
                default:
                    return(DefWindowProc(hWnd, uMsg, wParam, lParam));
            }
            break;
        case WM_DESTROY:
            ClrButton(1);
            ClrButton(2);
            PostQuitMessage(0);
            break;
        default:
            return(DefWindowProc(hWnd, uMsg, wParam, lParam));
    }

    return 0;
}

/* ボタン作成サブルーチン */
void PutButton(HWND hWndMain, int no, int left, int top, int width, int height, char *cap)
{
    hButton[no] = CreateWindow(
                    "button",                               // クラス名
                    cap,                                    // Window のタイトル
                    WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,  // Window のスタイル
                    left,                                   // Window の水平座標
                    top,                                    // Window の垂直座標
                    width,                                  // Window の幅
                    height,                                 // Window の高
                    hWndMain,                               // 親Window のハンドル
                    (HMENU)(BTN_ID0 + no),                  // Window ID
                    hInst,                                  // インスタンスハンドル
                    NULL);                                  //
    // 右側ボタンの処理を変更する(ボタンのサブクラス化)
    if(no == 2)
        BtnDefProc[no] = (WNDPROC)SetWindowLong(hButton[no], GWL_WNDPROC, (LONG)BtnProc_2);

    return;
}

/* ボタン削除サブルーチン */
void ClrButton(int no)
{
    DestroyWindow(hButton[no]);
    return;
}

/* 右側ボタンのボタンプロシージャ */
LRESULT CALLBACK BtnProc_2(HWND hBtn, UINT iMessage, WPARAM wParam, LPARAM lParam)
{
    HWND    hWnd;
    int     no;

    no = GetWindowLong(hBtn, GWL_ID);   //  ボタンのIDを取得
    switch(iMessage) {
        case WM_LBUTTONDOWN:            // 左クリック -> 無効
        case WM_LBUTTONDBLCLK:          // 左ダブルクリック -> 無効
            return 0;
        case WM_RBUTTONDOWN:            // 右クリック -> 有効
            hWnd = GetParent(hBtn);
            PostMessage(hWnd, WM_COMMAND, no, (LPARAM)hBtn);
            return 0;
        default:
            no -= BTN_ID0;
            return CallWindowProc(BtnDefProc[no], hBtn, iMessage, wParam, lParam);
    }
}

 Sample_C2.cpp メインウィンドウをクラス化 (緑色の部分は各 .cpp ファイル共通です)
TOP  
/** Sample_C2.cpp:ボタンを持つWindowsプログラム (by GARA) **/

#include <afxwin.h>
#include "Sample_C.h"

/* Define */
#define CLASS_NAME  "Sample_C2Class"    // クラス名
#define WIN_TITLE   "Sample_C2"         // タイトル

/* Global */
HINSTANCE   hInst;
HWND        hButton[3];
WNDPROC     BtnDefProc[3];

/* Proto Type */
void PutButton(HWND, int, int, int, int, int, char *);
void ClrButton(int);
LRESULT CALLBACK BtnProc_2(HWND, UINT, WPARAM, LPARAM);

/* ウィンドウクラスの宣言 */
class CMainFrame : public CFrameWnd     // ウィンドウクラス CWnd -> CFrameWnd
{
public:
    // コンストラクタ
    CMainFrame();
    // メンバ関数
    virtual BOOL PreCreateWindow(CREATESTRUCT&);
    // メッセージハンドラ
    afx_msg int  OnCreate(LPCREATESTRUCT);      // WM_CREATE に対応
    afx_msg void OnPaint();                     // WM_PAINT に対応
    afx_msg void OnBtn(UINT);                   // WM_COMMAND に対応(2対1)
    afx_msg void OnDestroy();                   // WM_DESTROY に対応
    DECLARE_MESSAGE_MAP()
};

/* メッセージマップの定義 */
BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)    // 第1引数:メッセージマップを所有するクラスの名前、第2引数:基本クラス名
    ON_WM_CREATE()
    ON_WM_PAINT()
    ON_COMMAND_RANGE(BTN_ID1, BTN_ID2, OnBtn)
    ON_WM_DESTROY()
END_MESSAGE_MAP()

/* アプリケーションクラスの宣言 */
class CMyApp : public CWinApp
{
public:
    virtual BOOL InitInstance();        // インスタンスを初期化する関数
};

/* ウィンドウクラスのメンバ */
// コンストラクタ
CMainFrame::CMainFrame()                // コンストラクタ
{
    Create(NULL, "");                   // ウィンドウの作成。第1引数:クラス名、第2引数:ウィンドウ名
}

// メンバ関数
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)  // PreCreateWindow() のオーバーライド
{
    Sample_A2.cpp と同じ 
}

// メッセージハンドラ
int CMainFrame::OnCreate(LPCREATESTRUCT cs)
{
    // インスタンスハンドルの取得
    hInst = AfxGetInstanceHandle();
    // ボタンの作成
    PutButton(m_hWnd, 1,  70, 100, 150, 30, "左クリックボタン");
    PutButton(m_hWnd, 2, 280, 100, 150, 30, "右クリックボタン");
    return 0;
}

void CMainFrame::OnPaint()          // OnPaint() のオーバーライド
{
    HWND        hWnd;
    HDC         hDC;
    PAINTSTRUCT ps;

    hWnd = m_hWnd;                  // m_hWnd は CWnd のメンバ変数
    ::BeginPaint(hWnd, &ps);        // ::(グローバルスコープ解決演算子)をつける
    hDC = ps.hdc;
    TextOut(hDC, 10, 10, "SDK -> MFC", 10);
    ::EndPaint(hWnd, &ps);
    return;
}

void CMainFrame::OnBtn(UINT wParam) // 独自メンバー関数(オーバーライドでない)
{
    HWND    hWnd;

    hWnd = m_hWnd;
    switch(LOWORD(wParam)) {
        case BTN_ID1:       // ボタン1
            ::MessageBox(hWnd, "左側のボタンが押されました", "ボタン", MB_OK);
            break;
        case BTN_ID2:       // ボタン2
            ::MessageBox(hWnd, "右側のボタンが押されました", "ボタン", MB_OK);
            break;
    }
    return;
}

void CMainFrame::OnDestroy()
{
    ClrButton(1);
    ClrButton(2);
    PostQuitMessage(0);
    return;
}

/* ボタン作成サブルーチン */
void PutButton(HWND hWndMain, int no, int left, int top, int width, int height, char *cap)
{
    hButton[no] = CreateWindow(
                    "button",                               // クラス名
                    cap,                                    // Window のタイトル
                    WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,  // Window のスタイル
                    left,                                   // Window の水平座標
                    top,                                    // Window の垂直座標
                    width,                                  // Window の幅
                    height,                                 // Window の高
                    hWndMain,                               // 親Window のハンドル
                    (HMENU)(BTN_ID0 + no),                  // Window ID
                    hInst,                                  // インスタンスハンドル
                    NULL);                                  //
    // 右側ボタンの処理を変更する(ボタンのサブクラス化)
    if(no == 2)
        BtnDefProc[no] = (WNDPROC)SetWindowLong(hButton[no], GWL_WNDPROC, (LONG)BtnProc_2);

    return;
}

/* ボタン削除サブルーチン */
void ClrButton(int no)
{
    DestroyWindow(hButton[no]);
    return;
}

/* アプリケーションクラスのメンバ */
// メンバ関数
BOOL CMyApp::InitInstance()         // InitInstance() のオーバーライド
{
    m_pMainWnd = new CMainFrame();          // メインウィンドウの作成
    m_pMainWnd->ShowWindow(m_nCmdShow);
    m_pMainWnd->UpdateWindow();

    return TRUE;
}


/* アプリケーションの生成(実行)*/

CMyApp MyApp;


/* 右側ボタンのボタンプロシージャ */
LRESULT CALLBACK BtnProc_2(HWND hBtn, UINT iMessage, WPARAM wParam, LPARAM lParam)
{
    HWND    hWnd;
    int     no;

    no = GetWindowLong(hBtn, GWL_ID);   //  ボタンのIDを取得
    switch(iMessage) {
        case WM_LBUTTONDOWN:            // 左クリック -> 無効
        case WM_LBUTTONDBLCLK:          // 左ダブルクリック -> 無効
            return 0;
        case WM_RBUTTONDOWN:            // 右クリック -> 有効
            hWnd = GetParent(hBtn);
            PostMessage(hWnd, WM_COMMAND, no, (LPARAM)hBtn);   // hBtn を渡さないと Debugモードで実行時アボート
            return 0;
        default:
            no -= BTN_ID0;
            return CallWindowProc(BtnDefProc[no], hBtn, iMessage, wParam, lParam);
    }
}


 Sample_C3.cpp メインウィンドウとボタンをクラス化 (緑色の部分は各 .cpp ファイル共通です)
TOP  
・ OnPaint で CPaintDC を使用しています。

/** Sample_C3.cpp:ボタンを持つWindowsプログラム (by GARA) **/

#include <afxwin.h>
#include "Sample_C.h"

/* Define */
#define CLASS_NAME  "Sample_C3Class"    // クラス名
#define WIN_TITLE   "Sample_C3"         // タイトル

/* Global */
WNDPROC     BtnDefProc[3];

/* Proto Type */
LRESULT CALLBACK BtnProc_2(HWND, UINT, WPARAM, LPARAM);

/* ウィンドウクラスの宣言 */
class CMainFrame : public CFrameWnd     // ウィンドウクラス CWnd -> CFrameWnd
{
private:
    CButton     *pButton[3];            // 動的に作成する場合
//  CButton     cButton[3];             // 静的に作成する場合
public:
    // コンストラクタ
    CMainFrame();
    // メンバ関数
    virtual BOOL PreCreateWindow(CREATESTRUCT&);
    // メッセージハンドラ
    afx_msg int  OnCreate(LPCREATESTRUCT);      // WM_CREATE に対応
    afx_msg void OnPaint();                     // WM_PAINT に対応
    afx_msg void OnBtn(UINT);                   // WM_COMMAND に対応(2対1)
    afx_msg void OnDestroy();                   // WM_DESTROY に対応
    DECLARE_MESSAGE_MAP()
};

/* メッセージマップの定義 */
BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)    // 第1引数:メッセージマップを所有するクラス名、第2引数:基本クラス名
    ON_WM_CREATE()
    ON_WM_PAINT()
    ON_COMMAND_RANGE(BTN_ID1, BTN_ID2, OnBtn)
    ON_WM_DESTROY()
END_MESSAGE_MAP()

/* アプリケーションクラスの宣言 */
class CMyApp : public CWinApp
{
public:
    virtual BOOL InitInstance();        // インスタンスを初期化する関数
};

/* ウィンドウクラスのメンバ */
// コンストラクタ
CMainFrame::CMainFrame()                // コンストラクタ
{
    Create(NULL, "");                   // ウィンドウの作成。第1引数:クラス名、第2引数:ウィンドウ名
}

// メンバ関数
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)  // PreCreateWindow() のオーバーライド
{
    Sample_A2.cpp と同じ 
}

// メッセージハンドラ
int CMainFrame::OnCreate(LPCREATESTRUCT cs)
{
    DWORD   style;

    style = WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON;
    // ボタンを動的に作成
    pButton[1] = new CButton();
    pButton[1]->Create("左クリックボタン", style, CRect( 70, 100, 220, 130), this, BTN_ID1);
    pButton[2] = new CButton();
    pButton[2]->Create("右クリックボタン", style, CRect(280, 100, 430, 130), this, BTN_ID2);
    // ボタンを静的に作成
//  cButton[1].Create("左クリックボタン", style, CRect( 70, 100, 220, 130), this, BTN_ID1);
//  cButton[2].Create("右クリックボタン", style, CRect(280, 100, 430, 130), this, BTN_ID2);
    // 右側ボタンのサブクラス化
    BtnDefProc[2] = (WNDPROC)SetWindowLong(pButton[2]->m_hWnd, GWL_WNDPROC, (LONG)BtnProc_2);   // 動的
//  BtnDefProc[2] = (WNDPROC)SetWindowLong(cButton[2].m_hWnd, GWL_WNDPROC, (LONG)BtnProc_2);    // 静的

    return 0;
}

void CMainFrame::OnPaint()          // OnPaint() のオーバーライド
{
    CPaintDC    dc(this);   // CPaintDC のコンストラクタの引数に this(CMainFrame オブジェクトへのポインタ)をセット

    dc.TextOut(10, 10, "SDK -> MFC", 10);
    return;
}

void CMainFrame::OnBtn(UINT wParam) // 独自メンバー関数(オーバーライドでない)
{
    switch(LOWORD(wParam)) {
        case BTN_ID1:       // ボタン1
            MessageBox("左側のボタンが押されました", "ボタン", MB_OK);      // CWnd のメンバ関数を使用
            break;
        case BTN_ID2:       // ボタン2
            MessageBox("右側のボタンが押されました", "ボタン", MB_OK);      // CWnd のメンバ関数を使用
            break;
    }
    return;
}

void CMainFrame::OnDestroy()
{
    delete pButton[1];      // 動的に作成した場合
    delete pButton[2];      // 動的に作成した場合
    PostQuitMessage(0);
    return;
}

/* アプリケーションクラスのメンバ */
// メンバ関数
BOOL CMyApp::InitInstance()         // InitInstance() のオーバーライド
{
    m_pMainWnd = new CMainFrame();          // メインウィンドウの作成
    m_pMainWnd->ShowWindow(m_nCmdShow);
    m_pMainWnd->UpdateWindow();

    return TRUE;
}


/* アプリケーションの生成(実行)*/

CMyApp MyApp;


/* 右側ボタンのボタンプロシージャ */
LRESULT CALLBACK BtnProc_2(HWND hBtn, UINT iMessage, WPARAM wParam, LPARAM lParam)
{
    HWND    hWnd;
    int     no;

    no = GetWindowLong(hBtn, GWL_ID);   //  ボタンのIDを取得
    switch(iMessage) {
        case WM_LBUTTONDOWN:            // 左クリック -> 無効
        case WM_LBUTTONDBLCLK:          // 左ダブルクリック -> 無効
            return 0;
        case WM_RBUTTONDOWN:            // 右クリック -> 有効
            hWnd = GetParent(hBtn);
            PostMessage(hWnd, WM_COMMAND, no, (LPARAM)hBtn);   // hBtn を渡さないと Debugモードで実行時アボート
            return 0;
        default:
            no -= BTN_ID0;
            return CallWindowProc(BtnDefProc[no], hBtn, iMessage, wParam, lParam);
    }
}



BACK  TOP