MFCコントロール - DDV
概要
DDV (Dialog Data Validation) は、MFCアプリケーションにおけるユーザ入力データの検証機能である。
MFCアプリケーションにおけるデータ検証の基盤として、ユーザインターフェースを支援する機能である。
DDX (Dialog Data eXchange) と密接に連携して動作しており、データの整合性と有効性を確保する。
DDVの仕組みでは、UpdateData(TRUE)
メソッドを実行した (コントロールからメンバ変数にデータが転送される) 場合に、指定された検証ルールに基づいてデータの妥当性がチェックされる。
検証に失敗した場合は、自動的にエラーメッセージが表示されて、該当のコントロールにフォーカスが設定される。
検証機能として、数値の範囲、文字列の長さ、必須入力等が組み込まれている。
例えば、DDV_MinMaxInt
は整数値の範囲を検証、DDV_MaxChars
は文字列の最大長を制限する。
また、カスタム検証ロジックを実装することも可能であり、アプリケーション固有の複雑な検証要件にも対応できる。
カスタム検証ロジックは、DoDataExchange
メソッド内で独自の検証関数を呼び出す、あるいは、条件分岐を使用して実装する。
エラーハンドリングにおいては、DDVは例外を使用してバリデーションの失敗を通知するため、try-catch句を使用して例外を処理することができる。
これにより、エラーメッセージを提供する、あるいは、特定の状況下での代替処理を実装することが可能になる。
また、DDVはフォーム全体の検証も可能であり、UpdateDataメソッドの実行時に全ての検証ルールが順番にチェックされて、1つでも失敗すると処理が中断される。
これにより、データの一貫性を確保して、不正なデータがアプリケーション内部に入り込むのを防ぐことができる。
文字列の長さ
void CMyDialog::DoDataExchange(CDataExchange *pDX)
{
CDialog::DoDataExchange(pDX);
// 文字列の長さに検証例 (5文字以上20文字以下)
DDX_Text(pDX, IDC_EDIT_NAME, m_strName);
DDV_MaxChars(pDX, m_strName, 20);
DDV_MinChars(pDX, m_strName, 5);
}
数値範囲の検証
void CMyDialog::DoDataExchange(CDataExchange *pDX)
{
CDialog::DoDataExchange(pDX);
// 数値範囲の検証例 (0〜120)
DDX_Int(pDX, IDC_EDIT_AGE, m_nAge);
DDV_MinMaxInt(pDX, m_nAge, 0, 120);
// 浮動小数範囲の検証例 (0.0〜1000000.0)
DDX_Text(pDX, IDC_EDIT_SALARY, m_dSalary);
DDV_MinMaxDouble(pDX, m_dSalary, 0.0, 1000000.0);
}
カスタム検証
// カスタムバリデーション 1
void AFXAPI DDV_EmailAddress(CDataExchange* pDX, const CString& value)
{
// コントロールからデータを取得する場合のみチェック
if (pDX->m_bSaveAndValidate) {
// 簡易的なメールアドレス確認
if (value.Find('@') == -1 || value.Find('.') == -1) {
AfxMessageBox(_T("有効なメールアドレスを入力してください"));
pDX->Fail(); // バリデーション失敗
}
}
}
void CMyDialog::DoDataExchange(CDataExchange *pDX)
{
CDialog::DoDataExchange(pDX);
DDX_Text(pDX, IDC_EDIT_EMAIL, m_strEmail);
DDV_EmailAddress(pDX, m_strEmail);
// 必須入力チェック
DDX_Text(pDX, IDC_EDIT_REQUIRED, m_strRequired);
if (pDX->m_bSaveAndValidate && m_strRequired.IsEmpty()) {
AfxMessageBox(_T("この項目は必須です"));
pDX->Fail();
}
}
// カスタムバリデーション 2
bool CMyDialog::IsValidFormat(const CString &data)
{
// 例: 文字列が入力されているかどうかの検証
if (data.IsEmpty()) return false;
// 例: 文字種の検証
for (int i = 0; i < data.GetLength(); i++) {
if (!_istalnum(data[i]) && data[i] != '-' && data[i] != '_') {
return false;
}
}
// 例: 文字列の長さの検証
if (data.GetLength() > 50) return false;
// 例: 予約語の検証
if (data.CompareNoCase(_T("admin")) == 0 || data.CompareNoCase(_T("system")) == 0) {
return false;
}
// 例: 郵便番号フォーマットの検証 (例: 123-4567)
// 文字列の長さ
if (data.GetLength() != 8) return false;
// 形式 (数字3文字 - 数字4文字)
for (int i = 0; i < 8; i++) {
if (i == 3) {
if (data[i] != '-') return false;
}
else {
if (!_istdigit(data[i])) return false;
}
}
// 例: 電話番号フォーマットの検証 (例: 03-1234-5678)
// 正規表現の使用
CRegExp regExp;
regExp.Pattern = _T("^\\d{2,4}-\\d{2,4}-\\d{4}$");
return regExp.Test(data);
// 例: 日付フォーマットの検証 (例: 2024/01/13)
if (data.GetLength() != 10) return false;
// 年月日を分解
int year = _ttoi(data.Left(4));
int month = _ttoi(data.Mid(5, 2));
int day = _ttoi(data.Mid(8, 2));
// 区切り文字 (例: /) の検証
if (data[4] != '/' || data[7] != '/') return false;
// 値の範囲の検証
if (year < 1900 || year > 2100) return false;
if (month < 1 || month > 12) return false;
if (day < 1 || day > 31) return false;
return true;
}
void CMyDialog::DoDataExchange(CDataExchange *pDX)
{
CDialog::DoDataExchange(pDX);
DDX_Text(pDX, IDC_EDIT_DATA, m_strData);
if (pDX->m_bSaveAndValidate) {
// カスタム検証ロジック
if (!IsValidFormat(m_strData)) {
AfxMessageBox(_T("データ形式が不正です"));
pDX->Fail();
}
}
}