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 プログラムはクラスの組み合わせ >
『につづく!』
「それを続けていくことで、大きなプログラムが自然とできるわけです」
『ホントかなー、結局私、そういうの作ってなくない?』
「ギク」