MFCコントロール - DDV

提供:MochiuWiki - SUSE, Electronic Circuit, PCB
ナビゲーションに移動 検索に移動

概要

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();
       }
    }
 }