Mesoscopic Programming

タコさんプログラミング専門

ヌメロン製作講座第5回:グリッドクラスの作成

今回は本アプリケーションの肝であるグリッドクラスについて解説します。

ちなみに、そろそろソースコードが大きくなってきたのでここには解説に必要な変更点のみ掲載します。ビルドチェック済みの完全なソースファイルは、それぞれのファイル名にリンク(テキスト形式)しましたので使ってください。

グリッドクラスを実装すると、以下のようにやっとアプリらしい画面が表示されます。

f:id:hidakas1961:20120917160328j:plain:w200

ソースコードを見たいときは以下のリンクをクリックしてください。

main.hmain.cpp

グリッドクラス(calss Grid)

グリッドクラスはアプリケーションの表示と入力を管理します。
イメージとしてはエクセルのような表計算ソフトを思い出して下さい。

class Grid
{
public :

    HWND    hwnd;
    SHORT   maxCell;
    RECT    rect;
    POINT   offset;

    virtual Cell    * GetCells() = 0;
    virtual VOID    Init( HWND hWnd );
    virtual VOID    MakeGrid();
    virtual BOOL    CanSelectCell( Cell & cell );
    virtual VOID    Draw( HDC hdc );
};

class SetGrid : public Grid
{
public :

    static const int W1 = 70;
    static const int W2 = 270;
    static const int W3 = 20;
    static const int W4 = 26;
    static const int W5 = 59;
    static const int W6 = 59;
    static const int W7 = 58;
    static const int W8 = 46;
    static const int L1 = ( W1 );
    static const int L2 = ( L1 + W2 + 6 );
    static const int L3 = ( L2 + 195 );
    static Cell      cells[];

    Cell * GetCells() { return cells; }
};

class Grid は抽象クラスで、class SetGrid が今回使用している設定画面用のグリッドクラスです。今後、情報グリッドクラスと棋譜データグリッドクラス、分析データグリッドクラスが追加されます。

グリッドにはセルデータが必要なので基底クラスだけでは何もできません。従って派生クラスでは、純粋仮想関数の GetCells() を実装してセルデータアドレスを返す必要があります。

セルデータは静的データとして定義可能なように、明示的に仮想関数を含まないことを示す struct で定義してあります。*1

struct Cell
{
    CellID  cid;
    LPVOID  param;
    LONG    width;
    LONG    height;
    LONG    left;
    LONG    top;

    VOID    Draw( HDC hdc, POINT offset );
    BOOL    DrawFrame( HDC hdc, RECT rc );
    BOOL    DrawContent( HDC hdc, RECT rc );
    VOID    GetRect( RECT & rc, POINT offset );
    BOOL    GetText( PTCHAR text );
    ParamID GetParamID() { return * ( ParamID * ) & param; }
};

メンバ関数はデータ領域を必要としない*2のでこの場合サイズは 24 Bytes ですか。
設定画面グリッド(class SetGrid)の場合は、以下のようなセルデータ定義になります。

Cell SetGrid :: cells[] =
{
    { CELL_LABEL,       _T( "プレイ" ),                         W1 },
    { CELL_BUTTON,      ( LPVOID ) PARAM_START_BUTTON },
    { CELL_BUTTON,      ( LPVOID ) PARAM_END_BUTTON },
    { CELL_BUTTON,      ( LPVOID ) PARAM_NEW_BUTTON },
    { CELL_NEWLINE },

    { CELL_LABEL,       _T( "棋譜データ" ),                     W1 },
    { CELL_BUTTON,      ( LPVOID ) PARAM_LOAD_BUTTON },
    { CELL_BUTTON,      ( LPVOID ) PARAM_SAVE_BUTTON },
    { CELL_BUTTON,      ( LPVOID ) PARAM_CLEAR_BUTTON },
    { CELL_SEPARATOR },

    { CELL_LABEL,       _T( "タイトル" ),                       W1 },
    { CELL_EDIT,        ( LPVOID ) PARAM_TITLE,                 W2 },
    { CELL_NEWLINE },

    { CELL_LABEL,       _T( "設定桁数" ),                       W1 },
    { CELL_UPDOWN,      ( LPVOID ) PARAM_COLUMN,                W3 },
    { CELL_NEWLINE },

    { CELL_LABEL,       _T( "ルール" ),                         W1 },
    { CELL_COMBO,       ( LPVOID ) PARAM_RULE,                  W2 },
    { CELL_SEPARATOR2 },

    { CELL_LABEL,       _T( "先攻" ),                           0, 0, L1 },
    { CELL_LABEL,       _T( "後攻" ),                           0, 0, L2 },
    { CELL_NEWLINE2 },

    { CELL_LABEL,       _T( "プレイヤー名" ),                   W1 },
    { CELL_EDIT,        ( LPVOID ) PARAM_NAME_FIRST,            W2 },
    { CELL_EDIT,        ( LPVOID ) PARAM_NAME_SECOND,           W2, 0, L2 },
    { CELL_NEWLINE },

    { CELL_LABEL,       _T( "タイプ" ),                         W1 },
    { CELL_COMBO,       ( LPVOID ) PARAM_TYPE_FIRST,            W2 },
    { CELL_COMBO,       ( LPVOID ) PARAM_TYPE_SECOND,           W2, 0, L2 },
    { CELL_NEWLINE },

    { CELL_LABEL,       _T( "カード" ),                         W1 },
    { CELL_RIGHT,       _T( "0 x" ),                            0 },
    { CELL_UPDOWN,      ( LPVOID ) PARAM_CARD0_FIRST,           W3 },
    { CELL_RIGHT,       _T( "1 x" ),                            W4 },
    { CELL_UPDOWN,      ( LPVOID ) PARAM_CARD1_FIRST,           W3 },
    { CELL_RIGHT,       _T( "2 x" ),                            W4 },
    { CELL_UPDOWN,      ( LPVOID ) PARAM_CARD2_FIRST,           W3 },
    { CELL_RIGHT,       _T( "3 x" ),                            W4 },
    { CELL_UPDOWN,      ( LPVOID ) PARAM_CARD3_FIRST,           W3 },
    { CELL_RIGHT,       _T( "4 x" ),                            W4 },
    { CELL_UPDOWN,      ( LPVOID ) PARAM_CARD4_FIRST,           W3 },
    { CELL_RIGHT,       _T( "0 x" ),                            0, 0, L2 },
    { CELL_UPDOWN,      ( LPVOID ) PARAM_CARD0_SECOND,          W3 },
    { CELL_RIGHT,       _T( "1 x" ),                            W4 },
    { CELL_UPDOWN,      ( LPVOID ) PARAM_CARD1_SECOND,          W3 },
    { CELL_RIGHT,       _T( "2 x" ),                            W4 },
    { CELL_UPDOWN,      ( LPVOID ) PARAM_CARD2_SECOND,          W3 },
    { CELL_RIGHT,       _T( "3 x" ),                            W4 },
    { CELL_UPDOWN,      ( LPVOID ) PARAM_CARD3_SECOND,          W3 },
    { CELL_RIGHT,       _T( "4 x" ),                            W4 },
    { CELL_UPDOWN,      ( LPVOID ) PARAM_CARD4_SECOND,          W3 },
    { CELL_NEWLINE },

    { CELL_RIGHT,       _T( "5 x" ),                            0, 0, L1 },
    { CELL_UPDOWN,      ( LPVOID ) PARAM_CARD5_FIRST,           W3 },
    { CELL_RIGHT,       _T( "6 x" ),                            W4 },
    { CELL_UPDOWN,      ( LPVOID ) PARAM_CARD6_FIRST,           W3 },
    { CELL_RIGHT,       _T( "7 x" ),                            W4 },
    { CELL_UPDOWN,      ( LPVOID ) PARAM_CARD7_FIRST,           W3 },
    { CELL_RIGHT,       _T( "8 x" ),                            W4 },
    { CELL_UPDOWN,      ( LPVOID ) PARAM_CARD8_FIRST,           W3 },
    { CELL_RIGHT,       _T( "9 x" ),                            W4 },
    { CELL_UPDOWN,      ( LPVOID ) PARAM_CARD9_FIRST,           W3 },
    { CELL_RIGHT,       _T( "5 x" ),                            0, 0, L2 },
    { CELL_UPDOWN,      ( LPVOID ) PARAM_CARD5_SECOND,          W3 },
    { CELL_RIGHT,       _T( "6 x" ),                            W4 },
    { CELL_UPDOWN,      ( LPVOID ) PARAM_CARD6_SECOND,          W3 },
    { CELL_RIGHT,       _T( "7 x" ),                            W4 },
    { CELL_UPDOWN,      ( LPVOID ) PARAM_CARD7_SECOND,          W3 },
    { CELL_RIGHT,       _T( "8 x" ),                            W4 },
    { CELL_UPDOWN,      ( LPVOID ) PARAM_CARD8_SECOND,          W3 },
    { CELL_RIGHT,       _T( "9 x" ),                            W4 },
    { CELL_UPDOWN,      ( LPVOID ) PARAM_CARD9_SECOND,          W3 },
    { CELL_NEWLINE },

    { CELL_LABEL,       _T( "アイテム" ),                       W1 },
    { CELL_RIGHT,       _T( "High&Low x" ),                     W5 },
    { CELL_UPDOWN,      ( LPVOID ) PARAM_HIGHLOW_FIRST,         W3 },
    { CELL_RIGHT,       _T( "Double x" ),                       W6 },
    { CELL_UPDOWN,      ( LPVOID ) PARAM_DOUBLE_FIRST,          W3 },
    { CELL_RIGHT,       _T( "Target x" ),                       W7 },
    { CELL_UPDOWN,      ( LPVOID ) PARAM_TARGET_FIRST,          W3 },
    { CELL_RIGHT,       _T( "High&Low x" ),                     W5, 0, L2 },
    { CELL_UPDOWN,      ( LPVOID ) PARAM_HIGHLOW_SECOND,        W3 },
    { CELL_RIGHT,       _T( "Double x" ),                       W6 },
    { CELL_UPDOWN,      ( LPVOID ) PARAM_DOUBLE_SECOND,         W3 },
    { CELL_RIGHT,       _T( "Target x" ),                       W7 },
    { CELL_UPDOWN,      ( LPVOID ) PARAM_TARGET_SECOND,         W3 },
    { CELL_NEWLINE },

    { CELL_RIGHT,       _T( "Slash x" ),                        W5, 0, L1 },
    { CELL_UPDOWN,      ( LPVOID ) PARAM_SLASH_FIRST,           W3 },
    { CELL_RIGHT,       _T( "Shuffle x" ),                      W6 },
    { CELL_UPDOWN,      ( LPVOID ) PARAM_SHUFFLE_FIRST,         W3 },
    { CELL_RIGHT,       _T( "Change x" ),                       W7 },
    { CELL_UPDOWN,      ( LPVOID ) PARAM_CHANGE_FIRST,          W3 },
    { CELL_RIGHT,       _T( "Slash x" ),                        W5, 0, L2 },
    { CELL_UPDOWN,      ( LPVOID ) PARAM_SLASH_SECOND,          W3 },
    { CELL_RIGHT,       _T( "Shuffle x" ),                      W6 },
    { CELL_UPDOWN,      ( LPVOID ) PARAM_SHUFFLE_SECOND,        W3 },
    { CELL_RIGHT,       _T( "Change x" ),                       W7 },
    { CELL_UPDOWN,      ( LPVOID ) PARAM_CHANGE_SECOND,         W3 },
    { CELL_NEWLINE },

    { CELL_LABEL,       _T( "設定ナンバー" ),                   W1 },
    { CELL_NUMBER,      ( LPVOID ) PARAM_OPEN_FIRST,            W8 },
    { CELL_NUMBER,      ( LPVOID ) PARAM_OPEN_SECOND,           W8, 0, L2 },
    { CELL_SEPARATOR },
    { CELL_NULL }
};

必要なセルデータを必要なだけ書いて最後に CELL_NULL で終了マークを定義します。
メンバ変数の CellID cid がセルの種類、LPVOID param が表示データ情報を表します。
表示位置とサイズである width、height、left、top については 0 ならばグリッドが勝手に計算します。
セルの種類と表示パラメータの定義は以下の通りです。

enum CellID
{
    CELL_NULL = 0,
    CELL_NEWLINE,
    CELL_NEWLINE2,
    CELL_SEPARATOR,
    CELL_SEPARATOR2,
    CELL_LABEL,
    CELL_RIGHT,
    CELL_BUTTON,
    CELL_EDIT,
    CELL_NUMBER,
    CELL_UPDOWN,
    CELL_COMBO,
    MAX_CELL
};

enum ParamID
{
    PARAM_NULL = 0,
    PARAM_START_BUTTON,
    PARAM_END_BUTTON,
    PARAM_NEW_BUTTON,
    PARAM_LOAD_BUTTON,
    PARAM_SAVE_BUTTON,
    PARAM_CLEAR_BUTTON,
    PARAM_TITLE,
    PARAM_COLUMN,
    PARAM_RULE,
    PARAM_NAME_FIRST,
    PARAM_NAME_SECOND,
    PARAM_TYPE_FIRST,
    PARAM_TYPE_SECOND,
    PARAM_CARD0_FIRST,
    PARAM_CARD1_FIRST,
    PARAM_CARD2_FIRST,
    PARAM_CARD3_FIRST,
    PARAM_CARD4_FIRST,
    PARAM_CARD5_FIRST,
    PARAM_CARD6_FIRST,
    PARAM_CARD7_FIRST,
    PARAM_CARD8_FIRST,
    PARAM_CARD9_FIRST,
    PARAM_CARD0_SECOND,
    PARAM_CARD1_SECOND,
    PARAM_CARD2_SECOND,
    PARAM_CARD3_SECOND,
    PARAM_CARD4_SECOND,
    PARAM_CARD5_SECOND,
    PARAM_CARD6_SECOND,
    PARAM_CARD7_SECOND,
    PARAM_CARD8_SECOND,
    PARAM_CARD9_SECOND,
    PARAM_HIGHLOW_FIRST,
    PARAM_DOUBLE_FIRST,
    PARAM_TARGET_FIRST,
    PARAM_SLASH_FIRST,
    PARAM_SHUFFLE_FIRST,
    PARAM_CHANGE_FIRST,
    PARAM_HIGHLOW_SECOND,
    PARAM_DOUBLE_SECOND,
    PARAM_TARGET_SECOND,
    PARAM_SLASH_SECOND,
    PARAM_SHUFFLE_SECOND,
    PARAM_CHANGE_SECOND,
    PARAM_OPEN_FIRST,
    PARAM_OPEN_SECOND,
    MAX_PARAM
};

かなり長くなったので今回はここまでとします。
続きは次回で。

*1: C++ では struct は class とほぼ同じですがマイルールでそう決めました

*2: たぶん