#pragma twice

KAB-studio > プログラミング > #pragma twice > 398 Version 18.11 コントロールとデータのやりとりをするクラスを作る

#pragma twice 398 Version 18.11 コントロールとデータのやりとりをするクラスを作る

前のページへ 表紙・目次へ 次のページへ

 Version 18.11
コントロールとデータのやりとりをするクラスを作る

前回は標準 C++ ライブラリの iostream 系クラスや std::string クラス
を使用して、 C ランタイムライブラリの代わりの処理をしてみました
……でもあまり便利になってないよーな……
というわけで、今回はその便利な機能を持つクラスを作ってみましょう
ええっ、そんなことできるの?
もちろん。まぁ MFC くらい便利にはできないけど、十分便利なクラスが
簡単に作れるから
おおー
これから作るのは、エディットボックスと値のやりとりをするための
CEditCtrl クラス
おお、なんだか MFC っぽくて本格的!
まずはこのクラスを作ります。 Version 18.03 ( No.390 ) と同じ方法で
ソースファイルとヘッダーファイルを追加してください。作成するファイル
は以下の2つです

・EditCtrl.h
・EditCtrl.cpp

で、これから作る CEditCtrl クラスは、以下のような機能を持っていま


・エディットボックスと一対一で結びつく
・GetInt() メンバ関数で整数値として値を取得する
・SetInt() メンバ関数で整数値をセットする
・IsError() メンバ関数でエラー状態を取得する

この機能を CEditCtrl クラスに持たせるので、 EditCtrl.h は以下のよ
うになります

// EditCtrl.h

// CEditCtrl クラス。
class CEditCtrl
{
    // このエディットボックスのウィンドウハンドル。
    HWND m_hWnd;
    // エラー状態。 TRUE ならエラー。
    BOOL m_bIsError;

public:
    // コンストラクタ。
    CEditCtrl( HWND p_hDlgWnd, int p_iId );
    // int 型の値として値を取得します。
    int GetInt();
    // int 型の値をセットします。
    void SetInt( int p_iData );
    // エラー状態を取得します。
    BOOL IsError();
};

一対一で結びつくから、エディットボックスのウィンドウハンドルを
メンバ変数として持つんだ
そういうこと。他にもエラー状態を取っておく m_bIsError メンバ変数も
持っています
あとはコンストラクタと、値を取得するのとセットするメンバ関数、エラー
取得するメンバ関数ね
 GetInt() 、 SetInt() メンバ関数は Version 16.05 ( No.332 ) の
【getter】【setter】とほとんど同じ
なるほど、エディットボックスをメンバ変数と考えるわけね
こういうのに合わせた方がメンバ関数の機能が分かりやすいし、引数や
戻り値もすぐ決まるから簡単かな。さて、実際の本体、 EditCtrl.cpp はこ
んな感じ

// EditCtrl.cpp
#include <Windows.h>
#include <string>
#include <sstream>
#include <strstream>
#include "EditCtrl.h"

// コンストラクタ。
CEditCtrl::CEditCtrl( HWND p_hDlgWnd, int p_iId )
    : m_bIsError( FALSE )
{
    // ウィンドウハンドルを取得します。
    m_hWnd = GetDlgItem( p_hDlgWnd, p_iId );
}

// int 型の値として値を取得します。
int CEditCtrl::GetInt()
{
    // エラーをリセットします。
    m_bIsError = FALSE;

    // エディットボックス用文字列を用意します。
    char pch[256];
    // 文字列を取得します。
    GetWindowText( m_hWnd, pch, 255 );
    // 文字列から数値として取り出すためのストリームを用意します。
    std::istrstream cIStrStream( pch );
    // int 型に変換します。
    int iData;
    cIStrStream >> iData;

    // 入力チェックを行います。
    if( cIStrStream.fail() )
    {
        m_bIsError = TRUE;
        return 0;
    }

    // 値を返します。
    return iData;
}

// int 型の値をセットします。
void CEditCtrl::SetInt( int p_iData )
{
    // 文字列変換するためのストリームを用意します。
    std::ostringstream cOStringStream;
    // 引数を文字列変換します。
    cOStringStream << p_iData;
    // 中にある std::string クラスの、参照を取り出します。
    std::string &rcStringAnswer = cOStringStream.str();
    // それをエディットボックスにセットします。
    SetWindowText( m_hWnd, rcStringAnswer.data() );
}

// エラー状態を取得します。
BOOL CEditCtrl::IsError()
{
    return m_bIsError;
}

んー、もしかしてほとんど OnEqual() メンバ関数と同じ?
そう、 CNewCalcDialog クラスの OnEqual() メンバ関数とかなりの部分
が似ています。違うのは

・ひとつのエディットボックスだけを対象にしている
・エディットボックスのウィンドウハンドルは m_hWnd メンバ変数を使用
・エラー状態をメンバ変数として保存する

ってところかな
えーっと、まず最初のは、 OnEqual() メンバ関数の時は IDC_E_LEFT 、
IDC_E_RIGHT 、 IDC_E_ANSWER の3つを同時に操作してたけど、このクラス
は一対一の関係だからひとつだけ、ってことだよね
そういうこと。だからシンプルになってます
次は……そっか、コンストラクタでエディットボックスの
ウィンドウハンドルを取得して、それを使ってるんだ
そう、 GetDlgItem() メンバ関数をコンストラクタで呼び出して、
ウィンドウハンドルを m_hWnd メンバ変数に取ってあるんです。それを
使い回すわけ
これもさっきの一対一の関係ねー。最後のは……これ?

// int 型の値として値を取得します。
int CEditCtrl::GetInt()
{
    // エラーをリセットします。
    m_bIsError = FALSE;

// 略

    // 入力チェックを行います。
    if( cIStrStream.fail() )
    {
        m_bIsError = TRUE;
        return 0;
    }

そう、この部分。まぁ簡単に言うと、 cIStrStream.fail() の結果を代わ
りに取っておく、ってところかな
そうしないとエラー情報が返せないんだね
 Version 13.05 ( No.241 ) で説明したように、エラーの返し方には色々
方法があるんだけど、今回はエラー状態を取っておくってことで、 
GetLastError() 関数の方法に近いかな
まぁ fail() メンバ関数と同じ方法だしね
さて、最後に使う側。 NewCalcDialog.cpp は以下のように修正します

// NewCalcDialog.cpp
#include <Windows.h>
#include <stdio.h>
#include "EditCtrl.h" // この行を追加。
#include "resource.h"
#include "Dialog.h"
#include "NewCalcDialog.h"

// 略

// = ボタンが押された時のイベントハンドラ。
void CNewCalcDialog::OnEqual()
{
    // 各エディットボックス用の、 CEditCtrl クラスの変数を
    // 用意します。
    CEditCtrl cEditCtrlLeft( m_hWnd, IDC_E_LEFT );
    CEditCtrl cEditCtrlRight( m_hWnd, IDC_E_RIGHT );
    CEditCtrl cEditCtrlAnswer( m_hWnd, IDC_E_ANSWER );

    // 入力値を取り出します。
    int iLeft = cEditCtrlLeft.GetInt();
    int iRight = cEditCtrlRight.GetInt();

        // 入力チェックを行います。
    if  ( 
            ( cEditCtrlLeft.IsError() ) ||
            ( cEditCtrlRight.IsError() )
        )
    {
        MessageBox
            ( m_hWnd
            , "入力に誤りがあります。"
            , "エラー"
            , MB_OK
            );
        return;
    }

    // 足した値を IDC_E_ANSWER にセットします。
    cEditCtrlAnswer.SetInt( iLeft + iRight );
}

お、かなりシンプルになった!
エディットボックスとのやりとりを CEditCtrl クラスにまとめたことで
かなりシンプルな感じになりました
……でも、これって結局プログラムを移しただけだよね
本当にそうかな?
え?

/*
    Preview Next Story!
*/
こうやって別クラス作るのってめんどい! でも
でも?
使うと便利で面白いかも
そう、それを少しずつ続けると……
つづけると?
というわけで次回
< Version 18.12 プログラムはクラスの組み合わせ >
につづく!
それを続けていくことで、大きなプログラムが自然とできるわけです
ホントかなー、結局私、そういうの作ってなくない?
ギク
 
del.icio.us 登録する
Yahoo!ブックマーク 詳細を表示 users
livedoorクリップ 詳細を表示 livedoorクリップ ブックマーク数
はてなブックマーク 詳細を表示 はてなブックマーク ブックマーク数
RSSに登録
del.icio.us 登録する
Yahoo!ブックマーク 詳細を表示 users
livedoorクリップ 詳細を表示 livedoorクリップ ブックマーク数
はてなブックマーク 詳細を表示 はてなブックマーク ブックマーク数
 
このページは、Visual C++ 6.0を用いた C++ 言語プログラミングの解説を行う#pragma twiceの一コンテンツです。
詳しい説明は#pragma twiceのトップページをご覧ください。