客户端数据校验器

本文中的validator.cpp存在2个bug,见"客户端数据校验器中的2个bug"一文.(2014-6-27)


1.用途

简化客户端输入/编辑操作的编程。可大幅减少代码量,并易于维护和扩展。
.支持从对象直接加载到控件和把控件数据更新到对象
.自动根据校验规则控制输入
.支持TEdit,TComboBox,TDatetimePicker

限制:
.仅支持对象的成员类型为基本数据类型和string

2..定义

头文件:validator.h

名字空间:ns_validator

#include <vcl.h>
#include <stdio.h>
#include <assert.h>
#include <string>
#include <vector>
#include <ComCtrls.hpp>
#pragma hdrstop

#include "NullForm.h"
#include "auto_pointer.h"
#include "code_table_mgr.h"

using namespace std;
//---------------------------------------------------------------------------
namespace ns_validator {

//---------------------------------------------------------------------------
///< 有效字符类型
///< 1-数字(0-9) 2-字母(a-z,A-Z) 9-指定字符(若干)
enum VALID_CHARSET_TYPE { CS_DIGIT=1,CS_ALPHA=2,CS_STRING=9};

//---------------------------------------------------------------------------
///< 有效字符规则
struct CValidCharSet {
    VALID_CHARSET_TYPE type_;
    string chars_; ///< 当type_==9时,表示有效的字符
};

//---------------------------------------------------------------------------
///< 数据绑定控件基类
class CBindControl {
public:
    virtual int CheckInput(char ch) { return 1; }
    virtual int CheckInput(char ch,char **out) { return 1; }
    virtual string GetValue() = 0; ///< 获取控件的值
    virtual void SetValue(const char *value) = 0; ///< 设置控件值
    virtual void SetOnKeyPress(TKeyPressEvent e) {}
    virtual void SetFocus() = 0;
};

//---------------------------------------------------------------------------
///< CEdit编辑框控件
class CEdit : public CBindControl {
    TEdit *control_;
public:
    CEdit(TEdit *control);

    void SetOnKeyPress(TKeyPressEvent e);
    int CheckInput(char ch,char **out);
    string GetValue();
    void SetValue(const char *value);
    void SetFocus() { control_->SetFocus(); }
};


//---------------------------------------------------------------------------
///< 通用码表类
struct CCodeTableBase {
    string code_; ///< 编码
    string name_; ///< 名称

    CCodeTableBase(const char *code,const char *name):code_(code),name_(name) {
    }
};

//---------------------------------------------------------------------------
///< CComboBox组合框控件
class CComboBox : public CBindControl {
    short flag_; ///< 0-不使用码表 1-使用码表的code_值 2-使用码表的name_值
    CCodeTableMgr<CCodeTableBase,string> *code_table_; ///< 码表

    TComboBox *control_;
public:
    CComboBox(TComboBox *control,short flag=0,CCodeTableMgr<CCodeTableBase,string> *code_table=0);

    string GetValue();
    void SetValue(const char *value);
    void SetFocus() { control_->SetFocus(); }
};

//---------------------------------------------------------------------------
///< CDateTimePicker日期时间选取控件
class CDateTimePicker : public CBindControl {
    TDateTimePicker *control_;
    short flag_; ///< 1-日期时间 2-日期 3-时间
public:
    CDateTimePicker(TDateTimePicker *control,int flag=1);
    string GetValue();
    void SetValue(const char *value);
    void SetFocus() { control_->SetFocus(); }
};

//---------------------------------------------------------------------------
///< 校验器基类
class CValidatorBase {
protected:
    CAutoVector<CValidCharSet*> v_ch_set_;  ///< 有效字符限定,如果为空则表示允许任何字符
    unsigned int max_len_;                  ///< 最大长度(0:表示不限制)
    unsigned int min_len_;                  ///<最小长度(0:表示不限制)

    bool null_flag_;                        ///< 是否允许为空

    TfrmNull *null_form_;                   ///< 用于检查按键的窗体(内部隐藏)
public:
    CBindControl *control_;                 ///< 绑定的控件
public:
    CValidatorBase();
    virtual ~CValidatorBase();

    ///< 设置最小长度
    void SetMinLength(unsigned int min_len) { min_len_ = min_len; }
    ///< 设置最大长度
    void SetMaxLength(unsigned int max_len) { max_len_ = max_len; }
    ///< 取最小长度
    unsigned int GetMinLength() const { return min_len_; }
    ///< 取最大长度
    unsigned int GetMaxLength() const { return max_len_; }

    ///< 设置有效字符
    void AddValidChar(VALID_CHARSET_TYPE type);
    void AddValidChar(const char *s);

    ///< 设置允许空标志
    void SetNullFlag(bool flag) { null_flag_ = flag; }
    ///< 取允许空标志
    bool GetNullFlag() const { return null_flag_; }

    ///< 绑定控件
    void BindControl(CBindControl *control);

    ///< 获取控件内容
    int GetText(string &text);

    ///< 设置控件内容
    void SetText(const char *text);

    int CheckChar(char ch); ///< 检查字符的有效性
    virtual int CheckInput(char ch);  ///< 检查是否可以接受输入字符
    virtual int Check(void *val,int flag=1) = 0;  ///< 校验值有效性 1-有效 0-无效
    virtual int CheckText(const char *text,int flag) = 0; ///< 校验值的有效性 flag=0时不检查最小值和最小长度(输入过程中)
};


//---------------------------------------------------------------------------
///< 数值范围模板类
template <class T> class CNumberRange {
protected:
    short  range_prop_; ///< 值范围属性 bit-0: 是否有最大限制 bit-1:是否有最小限制 bit-2:最大限制是否排除边界值(0-不排除 1-排除) bit3-最小限制是否排除边界值

    T max_value_; ///< 最大值
    T min_value_; ///< 最小值
public:
    CNumberRange() {
        range_prop_ = 0;
        max_value_ = 0;
        min_value_ = 0;
    }
    ///< 设置最大值
    void SetMaxValue(T value,short flag=0) {
        max_value_ = value;
        range_prop_ |= 1; ///< 有最大限制
        if (flag)
            range_prop_ |= 1<<2; ///< 是否排除边界值
    }
    ///< 设置最小值
    void SetMinValue(T value,short flag=0) {
        min_value_ = value;
        range_prop_ |= 1<<1;
        if (flag) {
            range_prop_ |= 1<<3;
        }
    }

    ///< 取最大值
    T GetMinValue() const { return min_value_; }
    ///< 取最小值
    T GetMaxValue() const { return max_value_; }

    ///< 取范围属性
    short GetRangeProp() const { return range_prop_; }

    ///< 检查一个值是否在范围内
    ///< flag=0不检查最小值
    bool Check(T value,short flag) {
        if (range_prop_&1) { ///< 有最大值限制
            if (range_prop_&(1<<2)) {///< 排除边界值
                if (value>max_value_)
                    return false;
            }
            else {
                if (value>=max_value_)
                    return false;
            }
        }
        if (flag) {
            if (range_prop_&(1<<1)) { ///< 有最小值限制
                if (range_prop_&(1<<3)) {///< 排除边界值
                    if (value<min_value_)
                        return false;
                }
                else {
                    if (value<=min_value_)
                        return false;
                }
            }
        }
        return true;
    }
 };

//---------------------------------------------------------------------------
///< 整数校验器
class CIntValidator : public CValidatorBase,public CNumberRange<long> {
public:
    CIntValidator();

    int Check(void *val,int flag);  ///< 校验合法性
    int CheckText(const char *text,int flag);
};


//---------------------------------------------------------------------------
///< 小数数值校验器
///< 长度包括符号位和小数点
class CDecimalValidator : public CValidatorBase,public CNumberRange<double> {
    unsigned short scale_; ///< 最大小数位数
public:
    CDecimalValidator();

    ///< 设置最大小数位数
    void SetScale(unsigned short scale) { scale_ = scale; }
    ///< 取最大小数位数
    unsigned short GetScale() const { return scale_; }

    int Check(void *val,int flag);
    int CheckText(const char *text,int flag);
};

//---------------------------------------------------------------------------
///< 字符串校验器
/// @todo 引入正则表达式,支持各种文本模式
class CStringValidator  : public CValidatorBase {
public:
    CStringValidator();
    CStringValidator(unsigned int min_len,unsigned int max_len);

    int Check(void *val,int flag);
    int CheckText(const char *text,int flag);
};

//---------------------------------------------------------------------------
///< 对象校验成员绑定信息
struct CValidatorBindInfo {
	unsigned short offset_; ///< 成员在对象中的偏移
    string desc_; ///< 成员描述
	string var_type_; ///< 变量类型,字段类型
    CValidatorBase *validator_; ///< 校验器
    CBindControl *control_; ///< 控件

    CValidatorBindInfo(unsigned short offset,const char *val_type,CValidatorBase *validator,const char *desc):offset_(offset),var_type_(val_type),validator_(validator),control_(0) {
        if (desc) desc_ = desc;
    }
    ~CValidatorBindInfo() {
        if (control_) delete control_;
    }
};

//---------------------------------------------------------------------------
#define ORM_FIELD_TYPE_INT		"int"
#define ORM_FIELD_TYPE_UINT		"uint"
#define ORM_FIELD_TYPE_SHORT	"short"
#define ORM_FIELD_TYPE_USHORT	"ushort"
#define ORM_FIELD_TYPE_LONG		"long"
#define ORM_FIELD_TYPE_ULONG	"ulong"
#define ORM_FIELD_TYPE_INT64	"int64"
#define ORM_FIELD_TYPE_UINT64	"uint64"
#define ORM_FIELD_TYPE_CHAR		"char"
#define ORM_FIELD_TYPE_UCHAR	"uchar"
#define ORM_FIELD_TYPE_STRING	"string"
#define ORM_FIELD_TYPE_BOOL		"bool"
#define ORM_FIELD_TYPE_FLOAT	"float"
#define ORM_FIELD_TYPE_DOUBLE	"double"
#define ORM_FIELD_TYPE_INT1		"int1"
#define ORM_FIELD_TYPE_UINT1	"uint1"

#define OFFSETOF(TYPE,VAR) (int)&(((TYPE*)0)->VAR)
#define NEW_VALIDATOR_BIND(TYPE,VAR,VAL_TYPE,CHECKER,DESC) \
    new  CValidatorBindInfo(OFFSETOF(TYPE,VAR),VAL_TYPE,CHECKER,DESC)

//---------------------------------------------------------------------------
///< 对象校验器
template <class T> class CObjectValidator {
    vector<CValidatorBindInfo*> bind_info_;

    int err_code_;                              ///< 校验失败的错误码(@todo 待定义)
    CValidatorBindInfo *err_vbi_;               ///< 校验失败的绑定项

    bool auto_hint_;                            ///< 校验失败时自动提示
    bool auto_focus_;                           ///< 自动设置焦点

    ///< 查找指定成员对应的绑定信息
    CValidatorBindInfo* Find(int offset);
public:
    CObjectValidator():err_code_(0),err_vbi_(0),auto_hint_(true),auto_focus_(true) {
    }
    ~CObjectValidator() {
        vector<CValidatorBindInfo*>::iterator iter = bind_info_.begin();
        while(iter!=bind_info_.end()) {
            delete *iter;
            iter++;
        }
    }
    ///< 设置(校验失败时)自动提示标志
    void SetAutoHint(bool value) { auto_hint_ = value; }
    ///< 设置(校验失败时)自动设置输入焦点标志
    void SetAutoFocus(bool value) { auto_focus_ = value;}

    ///< 设置指定成员的校验器
    int SetValidator(CValidatorBindInfo* v) {
        bind_info_.push_back(v);
        return 0;
    }

    ///< 绑定成员与控件
    int BindControl(int offset,CBindControl *control);

    ///< 控件支持: TEdit,
    int Update(T *obj); ///< 把控件内容更新对象
    int Load(T *obj); ///< 把对象内容加载到控件
    int Check(T *obj); ///< 检查对象值的有效性,@return 0-无效 1-有效

    string GetErrorInfo(); ///< 获取校验错误信息
};

//---------------------------------------------------------------------------
template <class T> string CObjectValidator<T>::GetErrorInfo() {
    string err;
    if (err_vbi_==0)
        return err;
    err += "数据项'";
    err += err_vbi_->desc_.c_str();
    err += "'无效";

    return err;
}

//---------------------------------------------------------------------------
template <class T> CValidatorBindInfo*  CObjectValidator<T>::Find(int offset) {
    vector<CValidatorBindInfo*>::iterator iter = bind_info_.begin();
    while(iter!=bind_info_.end()) {
        CValidatorBindInfo *vbi = *iter;
        if (vbi->offset_==offset)
            return vbi;
        iter++;
    }
    return 0;
}
//---------------------------------------------------------------------------
template <class T> int CObjectValidator<T>::BindControl(int offset,CBindControl *control) {
    CValidatorBindInfo* vbi = Find(offset);
    if (vbi==0)
        return -1;
    vbi->control_ = control;
    vbi->validator_->BindControl(control);

    return 0;
}
//---------------------------------------------------------------------------
template <class T> int CObjectValidator<T>::Update(T *obj) {
    vector<CValidatorBindInfo*>::iterator iter = bind_info_.begin();
    while(iter!=bind_info_.end()) {
        CValidatorBindInfo *vbi = *iter;
        if (vbi->control_==0) { ///< 如果成员未与控件绑定则不处理
            iter++;
            continue;
        }
        char *p = (char*)obj+vbi->offset_;
        string sVal;
        vbi->validator_->GetText(sVal);
		string type_name = vbi->var_type_.c_str();
		if (type_name==ORM_FIELD_TYPE_LONG||type_name==ORM_FIELD_TYPE_ULONG) {
			*(long*)p = atol(sVal.c_str());
		}
		else if (type_name==ORM_FIELD_TYPE_INT||type_name==ORM_FIELD_TYPE_UINT) {
			*(int*)p = atoi(sVal.c_str());
		} else if (type_name==ORM_FIELD_TYPE_SHORT||type_name==ORM_FIELD_TYPE_USHORT) {
			*(short*)p = (short)atoi(sVal.c_str());
		} else if (type_name==ORM_FIELD_TYPE_INT1||type_name==ORM_FIELD_TYPE_UINT1) {
			*p = sVal[0];
		}
		else if (type_name==ORM_FIELD_TYPE_FLOAT) {
			*(float*)p = (float)atof(sVal.c_str());
		} else if (type_name==ORM_FIELD_TYPE_DOUBLE) {
			*(double*)p = atof(sVal.c_str());
		} else if (type_name==ORM_FIELD_TYPE_STRING) {
			*(string*)p = sVal.c_str();
		} else if (type_name==ORM_FIELD_TYPE_CHAR||type_name==ORM_FIELD_TYPE_UCHAR) {
			strcpy(p,sVal.c_str());//,fb->fld_size_);
		} else if (type_name==ORM_FIELD_TYPE_INT64||type_name==ORM_FIELD_TYPE_UINT64) {
			*(__int64*)p = _atoi64(sVal.c_str());
		} else if (type_name==ORM_FIELD_TYPE_BOOL) {
			*(bool*)p = sVal[0]=='1';
		}
		else {
            iter++;    ///< 不支持的数据类型
            continue;
		}
        iter++;
    }
    return 0;
}


//---------------------------------------------------------------------------
template <class T> int CObjectValidator<T>::Load(T *obj) {
    vector<CValidatorBindInfo*>::iterator iter = bind_info_.begin();
    while(iter!=bind_info_.end()) {
        CValidatorBindInfo *vbi = *iter;
        char *p = (char*)obj+vbi->offset_;
		string type_name = vbi->var_type_.c_str();
        char buffer[20];
		if (type_name==ORM_FIELD_TYPE_LONG||type_name==ORM_FIELD_TYPE_ULONG) {
            sprintf(buffer,"%d",*(long*)p);
            vbi->validator_->SetText(buffer);
		}
		else if (type_name==ORM_FIELD_TYPE_INT||type_name==ORM_FIELD_TYPE_UINT) {
            sprintf(buffer,"%d",*(int*)p);
            vbi->validator_->SetText(buffer);
		} else if (type_name==ORM_FIELD_TYPE_SHORT||type_name==ORM_FIELD_TYPE_USHORT) {
            sprintf(buffer,"%d",*(short*)p);
            vbi->validator_->SetText(buffer);
		} else if (type_name==ORM_FIELD_TYPE_INT1||type_name==ORM_FIELD_TYPE_UINT1) {
            sprintf(buffer,"%c",*p);
            vbi->validator_->SetText(buffer);
		}
		else if (type_name==ORM_FIELD_TYPE_FLOAT) {
            vbi->validator_->SetText(p);
		} else if (type_name==ORM_FIELD_TYPE_DOUBLE) {
            sprintf(buffer,"%.3f",*(double*)p); ///< @todo: 根据长度定义确定格式
            vbi->validator_->SetText(buffer);
		} else if (type_name==ORM_FIELD_TYPE_STRING) {
            string s = *(string*)p;
            vbi->validator_->SetText(s.c_str());
		} else if (type_name==ORM_FIELD_TYPE_CHAR||type_name==ORM_FIELD_TYPE_UCHAR) {
            vbi->validator_->SetText(p);
		} else if (type_name==ORM_FIELD_TYPE_INT64||type_name==ORM_FIELD_TYPE_UINT64) {
            sprintf(buffer,"%I64d",*(__int64*)p);
            vbi->validator_->SetText(buffer);
		} else if (type_name==ORM_FIELD_TYPE_BOOL) {
            sprintf(buffer,"%d",*(bool*)p);
            vbi->validator_->SetText(buffer);
		}
		else {
            iter++;    ///< 不支持的数据类型
            continue;
		}

        iter++;
    }
    return 0;
}

//---------------------------------------------------------------------------
template <class T> int CObjectValidator<T>::Check(T *obj) {
    vector<CValidatorBindInfo*>::iterator iter = bind_info_.begin();
    while(iter!=bind_info_.end()) {
        CValidatorBindInfo *vbi = *iter;
        char *p = (char*)obj+vbi->offset_;
		string type_name = vbi->var_type_.c_str();
        int ret = 0;
		if (type_name==ORM_FIELD_TYPE_LONG||type_name==ORM_FIELD_TYPE_ULONG) {
			ret = vbi->validator_->Check((void*)*(long*)p);
		}
		else if (type_name==ORM_FIELD_TYPE_INT||type_name==ORM_FIELD_TYPE_UINT) {
			ret = vbi->validator_->Check((void*)*(int*)p);
		} else if (type_name==ORM_FIELD_TYPE_SHORT||type_name==ORM_FIELD_TYPE_USHORT) {
			ret = vbi->validator_->Check((void*)*(short*)p);
		} else if (type_name==ORM_FIELD_TYPE_INT1||type_name==ORM_FIELD_TYPE_UINT1) {
 			ret = vbi->validator_->Check((void*)*p);
		}
		else if (type_name==ORM_FIELD_TYPE_FLOAT) {
			ret = vbi->validator_->Check((void*)p);
		} else if (type_name==ORM_FIELD_TYPE_DOUBLE) {
			ret = vbi->validator_->Check((void*)p);
		} else if (type_name==ORM_FIELD_TYPE_STRING) {
            string s = *(string*)p;
			ret = vbi->validator_->Check((void*)s.c_str());
		} else if (type_name==ORM_FIELD_TYPE_CHAR||type_name==ORM_FIELD_TYPE_UCHAR) {
			ret = vbi->validator_->Check((void*)p);
		} else if (type_name==ORM_FIELD_TYPE_INT64||type_name==ORM_FIELD_TYPE_UINT64) {
			ret = vbi->validator_->Check((void*)*(__int64*)p);
		} else if (type_name==ORM_FIELD_TYPE_BOOL) {
			ret = vbi->validator_->Check((void*)*(bool*)p);
		}
		else {
            iter++;    ///< 不支持的数据类型
            continue;
		}

        if (ret==0) {
            err_vbi_  = vbi;
            if (auto_hint_) {
                string err_msg = GetErrorInfo();
                ShowMessage(err_msg.c_str());
            }
            if (auto_focus_) {
                vbi->validator_->control_->SetFocus();
            }
            return 0;
        }
        iter++;
    }
    return 1;
}

};


3.实现

实现文件:validator.cpp

#pragma hdrstop

#include "validator.h"
#include "NullForm.h"

using namespace ns_validator;
#pragma package(smart_init)
//---------------------------------------------------------------------------
CValidatorBase::CValidatorBase():max_len_(0),min_len_(0),control_(0),null_form_(0),null_flag_(true) {
}

//---------------------------------------------------------------------------
CValidatorBase::~CValidatorBase() {
    if (null_form_) delete null_form_;
}

//---------------------------------------------------------------------------
int CValidatorBase::CheckChar(char ch) {
    if (v_ch_set_.empty())
        return 1;

    CAutoVector<CValidCharSet*>::iterator iter = v_ch_set_.begin();
    while(iter!=v_ch_set_.end()) {
        CValidCharSet *vcs = *iter;
        switch(vcs->type_) {
            case CS_DIGIT:
                if (isdigit(ch))
                    return 1;
            case CS_ALPHA:
                if (isalpha(ch)==0)
                    return 1;
            default:
                if (strchr(vcs->chars_.c_str(),ch))
                    return 1;
        }
        iter++;
    }
    return 0;
}

//---------------------------------------------------------------------------
int CValidatorBase::CheckInput(char ch) { ///< 检查当前输入字符
    if (CheckChar(ch)==0) { ///< 字符是否有效
        return 0;
    }
    char *Buffer = 0;
    if (control_->CheckInput(ch,&Buffer)==0) {
        return 0;
    }
    int Size = strlen(Buffer);
    if (max_len_) {
        if (Size>max_len_)  {
            delete []Buffer;
            return 0;
        }
    }

    int ret = CheckText(Buffer,0);
    delete []Buffer;

    return ret;

}

//---------------------------------------------------------------------------
///< 设置有效字符
void CValidatorBase::AddValidChar(VALID_CHARSET_TYPE type) {
    CValidCharSet *vcs = new CValidCharSet;
    vcs->type_ = type;
    v_ch_set_.push_back(vcs);
}

//---------------------------------------------------------------------------
void CValidatorBase::AddValidChar(const char *s) {
    CValidCharSet *vcs = new CValidCharSet;
    vcs->type_ = CS_STRING;
    vcs->chars_ = s;
    v_ch_set_.push_back(vcs);
}

//---------------------------------------------------------------------------
void CValidatorBase::BindControl(CBindControl *control) {
    control_ = control;
    null_form_ = new TfrmNull(0);
    null_form_->Visible = false;
    null_form_->SetValidator(this);
    control_->SetOnKeyPress(null_form_->EditKeyPress);
}

//---------------------------------------------------------------------------
int CValidatorBase::GetText(string &text) {
    text = control_->GetValue();
    return 0;
}

//---------------------------------------------------------------------------
void CValidatorBase::SetText(const char *text) {
    control_->SetValue((char*)text);
}

//---------------------------------------------------------------------------
CIntValidator::CIntValidator() {
    AddValidChar(CS_DIGIT);
}

//---------------------------------------------------------------------------
int CIntValidator::Check(void *val,int flag) { ///< 校验合法性
    long nval = (long)val;
    return CNumberRange<long>::Check(nval,flag);
}

//---------------------------------------------------------------------------
int CIntValidator::CheckText(const char *text,int flag) {
    long val = atol(text);
    return Check((char*)val,flag);
}

//---------------------------------------------------------------------------
CDecimalValidator::CDecimalValidator():scale_(2) {
    AddValidChar(CS_DIGIT);
    AddValidChar("."); ///< 允许小数点
}

//---------------------------------------------------------------------------
int CDecimalValidator::Check(void *val,int flag) {
    double fval = *(double*)val;
    return  CNumberRange<double>::Check(fval,flag);
}

//---------------------------------------------------------------------------
int CDecimalValidator::CheckText(const char *text,int flag) {
    double val = atof(text);
    if (Check((void*)&val,flag)==0)
        return 0;

    if (scale_) {
        ///< 检查小数长度
        const char *p = strchr(text,'.');
        if (p) {
            int scale_n = strlen(p)-1;
            if (scale_n>scale_)
                return 0;
        }
    }

    return 1;
}

//---------------------------------------------------------------------------
CStringValidator::CStringValidator(){
}

//---------------------------------------------------------------------------
CStringValidator::CStringValidator(unsigned int min_len,unsigned int max_len) {
    min_len_ = min_len;
    max_len_ = max_len;
}

//---------------------------------------------------------------------------
int CStringValidator::Check(void *val,int flag) {
    const char *sz_val = (const char*)val;
    int len = strlen(sz_val);
    if (flag) {
        if (min_len_) {
            if (len<min_len_)
                return 0;
        }
    }
    if (max_len_) {
        if (len>max_len_)
            return 0;
    }

    if (!v_ch_set_.empty()) {  ///< 检查是否是有效字符
        const char *p = sz_val;
        while(*p!='\0') {
            if (CheckChar(*p)==0)
                return 0;
            p++;
        };
    }

    return 1;
}

//---------------------------------------------------------------------------
int CStringValidator::CheckText(const char *text,int flag) {
    return Check((char*)text,flag);
}


//---------------------------------------------------------------------------
CEdit::CEdit(TEdit *control):control_(control) {
}

//---------------------------------------------------------------------------
void CEdit::SetOnKeyPress(TKeyPressEvent e) {
    control_->OnKeyPress = e;
}

//---------------------------------------------------------------------------
int CEdit::CheckInput(char ch,char **out) {
    int Size = control_->GetTextLen(); ///< 当前已接收内容的长度
    int sel_pos = control_->SelStart;

    ///< 对接受此输入后的结果进行检查(不检查最小值和最小长度:因正在输入过程)
    char *Buffer = new char[Size+2];
    control_->GetTextBuf(Buffer,Size+2);

    int sel_len = control_->SelLength;
    if (sel_len>0) {
        memcpy(&Buffer[sel_pos],&Buffer[sel_pos+sel_len],Size-sel_pos-sel_len+1);
        Size = strlen(Buffer);
    }

    int k = Size;
    while(k>=sel_pos) {
        char ch = Buffer[k];
        Buffer[k+1] = ch;
        k--;
    }

    Buffer[sel_pos] = ch;
    Buffer[Size+1] = '\0';

    *out = Buffer;

    return 1;
}

//---------------------------------------------------------------------------
string CEdit::GetValue() {
    return control_->Text.c_str();
}

//---------------------------------------------------------------------------
void CEdit::SetValue(const char *value) {
    control_->Text = value;
}

//---------------------------------------------------------------------------
CComboBox::CComboBox(TComboBox *control,short flag,CCodeTableMgr<CCodeTableBase,string> *code_table)
    :control_(control),flag_(flag),code_table_(code_table) {
}
//---------------------------------------------------------------------------
string CComboBox::GetValue() {
//    assert(control_->ItemIndex!=-1);
    if (control_->ItemIndex==-1) {
        return string();
    }
    if (flag_==1) {
        int count = code_table_->GetSize();
        for (int i=0;i<count;i++) {
            CCodeTableBase *item = (*code_table_)[i];
            if (stricmp(item->name_.c_str(),control_->Text.c_str())) {
                return item->code_;
            }
        }
    }
    return control_->Text.c_str();
}

//---------------------------------------------------------------------------
void CComboBox::SetValue(const char *value) {
    if (flag_==1) {
        int count = code_table_->GetSize();
        for (int i=0;i<count;i++) {
            CCodeTableBase *item = (*code_table_)[i];
            if (stricmp(item->name_.c_str(),control_->Text.c_str())) {
                control_->ItemIndex = i;
                return;
            }
        }
    }
    control_->ItemIndex = -1;
}

//---------------------------------------------------------------------------
CDateTimePicker::CDateTimePicker(TDateTimePicker *control,int flag):control_(control),flag_(flag) {
}

//---------------------------------------------------------------------------
string CDateTimePicker::GetValue() {
    TDateTime dt = control_->DateTime;
    AnsiString result;
    switch(flag_) {
        case 1:
            result = dt.FormatString("yyyy-mm-dd hh:nn:ss");
            break;
        case 2:
            result = dt.FormatString("yyyy-mm-dd");
            break;
        case 3:
            result = dt.FormatString("hh:nn:ss");
            break;
    }
    return result.c_str();
}

//---------------------------------------------------------------------------
void CDateTimePicker::SetValue(const char *value) {
      AnsiString s(value);
      TDateTime dt(s);
      control_->DateTime = dt;
}

NullForm.cpp

void __fastcall TfrmNull::EditKeyPress(TObject *Sender, char &Key) {
    if (iscntrl(Key)) { ///< 删除等操作
        return;
    }
    assert(validator_!=0);
    if (validator_->CheckInput(Key)==0) {
        Key = 0;
        return;
    }
}



4.示例:
#include "validator.h"
using namespace ns_validator;

//---------------------------------------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{
    ///< 商品GTIN:不能为空,并且必须是13个字符宽
    CStringValidator *sv = new CStringValidator;
    sv->SetMinLength(13);
    sv->SetMaxLength(13);
    sv->SetNullFlag(false); ///< 不允许为空
    sv->AddValidChar(CS_DIGIT);
    ov_.SetValidator(NEW_VALIDATOR_BIND(CGYBGoods, m_strGoodsid,ORM_FIELD_TYPE_STRING,sv,"商品GTIN"));

    ///< 零售价:小数数值,长度(8,3)--长度8位(含小数点和小数位),小数位最大3位,只能是正数,有效字符:0-9,'.'
    CDecimalValidator *dv = new CDecimalValidator;
    dv->SetMaxLength(8);
    dv->SetScale(3);
    ov_.SetValidator(NEW_VALIDATOR_BIND(CGYBGoods,m_dRetailPrice,ORM_FIELD_TYPE_DOUBLE,dv,"建议零售价"));

    ///< 装箱数
    CIntValidator *iv = new CIntValidator;
    iv->SetMaxLength(6);
    ov_.SetValidator(NEW_VALIDATOR_BIND(CGYBGoods,m_iBoxCount,ORM_FIELD_TYPE_INT,iv,"装箱数"));

    ///< 税率
    dv = new CDecimalValidator;
    ov_.SetValidator(NEW_VALIDATOR_BIND(CGYBGoods,m_dTaxRate,ORM_FIELD_TYPE_DOUBLE,dv,"税率"));

    sv = new CStringValidator;
    ov_.SetValidator(NEW_VALIDATOR_BIND(CGYBGoods,m_strOrderBegin,ORM_FIELD_TYPE_STRING,sv,"订单开始日期"));

    sv = new CStringValidator;
    ov_.SetValidator(NEW_VALIDATOR_BIND(CGYBGoods,m_strOrderEnd,ORM_FIELD_TYPE_STRING,sv,"订单截止日期"));

    ///< 绑定控件
    ov_.BindControl(OFFSETOF(CGYBGoods, m_strGoodsid),new CEdit(edtGTIN));
    ov_.BindControl(OFFSETOF(CGYBGoods, m_dRetailPrice),new CEdit(edtPrice));
    ov_.BindControl(OFFSETOF(CGYBGoods, m_iBoxCount),new CEdit(edtBoxNum));

    ///< 税率绑定的是TComboBox
    ov_.BindControl(OFFSETOF(CGYBGoods, m_dTaxRate),new CComboBox(cbTaxRate,1,&tax_rate_code_tbl_));

    ///< 销售开始和截止日期绑定的是TDatTimePicker
    ov_.BindControl(OFFSETOF(CGYBGoods, m_strOrderBegin),new CDateTimePicker(dtpSaleBegin,2));
    ov_.BindControl(OFFSETOF(CGYBGoods, m_strOrderEnd),new CDateTimePicker(dtpSaleEnd,2));

    ///< 初始化税率码表
    tax_rate_code_tbl_.Add("1",new CCodeTableBase("1","0.015"));
    tax_rate_code_tbl_.Add("2",new CCodeTableBase("2","0.013"));
    int item_num = tax_rate_code_tbl_.GetSize();
    for (int i=0;i<item_num;i++) {
        CCodeTableBase *item = tax_rate_code_tbl_[i];
        cbTaxRate->Items->AddObject(item->name_.c_str(),(TObject*)item);
    }

    return;
}

//---------------------------------------------------------------------------
void __fastcall TForm1::btnOkClick(TObject *Sender)
{
    int ret = 0;
    ///< 把控件内容更新到对象    
    ret = ov_.Update(&goods_);

    ///< 从对象加载到控件
    goods_.m_strGoodsid = "134";
    goods_.m_dRetailPrice = 12.01;
    goods_.m_iBoxCount = 120;
    goods_.m_dTaxRate = 1;
    goods_.m_strOrderBegin = "2013-1-1";
    goods_.m_strOrderEnd = "2014-1-15";
    ret = ov_.Load(&goods_);

    ///< 校验对象数据
    ret = ov_.Check(&goods_);

    return;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值