Алекс Jenter - Программирование на Visual C++. Архив рассылки
- Название:Программирование на Visual C++. Архив рассылки
- Автор:
- Жанр:
- Издательство:неизвестно
- Год:неизвестен
- ISBN:нет данных
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Алекс Jenter - Программирование на Visual C++. Архив рассылки краткое содержание
РАССЫЛКА ЯВЛЯЕТСЯ ЧАСТЬЮ ПРОЕКТА RSDN, НА САЙТЕ КОТОРОГО ВСЕГДА МОЖНО НАЙТИ ВСЮ НЕОБХОДИМУЮ РАЗРАБОТЧИКУ ИНФОРМАЦИЮ, СТАТЬИ, ФОРУМЫ, РЕСУРСЫ, ПОЛНЫЙ АРХИВ ПРЕДЫДУЩИХ ВЫПУСКОВ РАССЫЛКИ И МНОГОЕ ДРУГОЕ.
Программирование на Visual C++. Архив рассылки - читать онлайн бесплатно полную версию (весь текст целиком)
Интервал:
Закладка:
BEGIN_DDX_MAP(CMyDialog)
DDX_TEXT_LEN(IDC_NAME, m_name, 20)
DDX_TEXT(IDC_ADDRESS, m_address)
DDX_UINT_RANGE(IDC_PHONE, m_phone, 0, 9999999)
END_DDX_MAP()
ПРИМЕЧАНИЕ
Если вы использовали MFC, вы, вероятно, заметили сходство карты DDX с виртуальной функцией CWnd::DoDataExchange. Они действительно похожи. Одно отличие состоит в том, что макросы WTL не используют вспомогательную структуру, аналогичную CDataExchangeиз mfc. Это несколько упрощает их использование. Второе отличие – в WTL собственно обмен и валидация объединены вместе, а в MFC им соответствуют различные функции ( DDX_*для обмена данными и DDV_*для валидации).
Вот и всё. Никакой дополнительной инициализации механизм DDX в WTL не требует. Чтобы выполнить обмен данными, используйте функцию DoDataExchange. Вот её прототип:
BOOL DoDataExchange(BOOL bSaveAndValidate = FALSE, UINT nCtlID = (UINT)-1)
Параметр bSaveAndValidateзадаёт направление обмена ( FALSEили DDX_LOADсоответствует записи значений из переменных в контролы, а TRUEили DDX_SAVE– из контролов в переменные). Второй параметр задаёт идентификатор контрола, с которым необходимо произвести обмен. Значение по умолчанию (-1) соответствует всем контролам, упомянутым в карте DDX. Функция DoDataExchangeвозвращает TRUE, если обмен данными был успешным, или FALSEв противном случае.
ПРИМЕЧАНИЕ
В MFC обмен данными осуществляет функция CWnd::UpdateData, похожая на DoDataExchangeиз wtl. Отличие в том, что функция UpdateDataне позволяет задавать идентификатор контрола. Вместо этого она всегда воздействует на все контролы, прописанные в функции CWnd::DoDataExchange. Реализация в wtl несколько гибче, но было бы ещё лучше, если бы разработчики WTL предусмотрели разбиение карты DDX на подкарты (как это сделано для карт сообщений). Часто в реальной программе требуется выполнить обмен данными не с одним контролом и не со всеми контролами, а с некоторым их подмножеством.
Иногда в процессе обмена данными возникают ошибки. Их делят на две разновидности: ошибки обмена (data exchange errors) и ошибки валидации (data validation errors). Ошибки обмена возникают, когда контрол не содержит значения, соответствующего типу связанной с ним переменной (например, поле ввода, связанное с переменной типа int, содержит пробелы или другие нецифровые символы). Ошибки валидации фиксируются в случае несоответствия передаваемого значения и наложенных на него ограничений (максимальная длина строки, минимальное и максимальное значение числа). В случае возникновения ошибки обмена вызывается виртуальная функция OnDataExchangeError, а при возникновении ошибки валидации – виртуальная функция OnDataValidateError. Дальнейший процесс обмена данными прерывается, а DoDataExchangeвозвращает FALSE, сигнализируя о неуспехе операции.
Класс CWinDataExchange<>предоставляет свои реализации функций OnDataExchangeErrorи OnDataValidateError. Они обе совершенно одинаковы.
// Overrideables
void OnDataExchangeError(UINT nCtrlID, BOOL /*bSave*/) {
// Override to display an error message
::MessageBeep((UINT)-1);
T* pT = static_cast(this);
::SetFocus(pT->GetDlgItem(nCtrlID));
}
void OnDataValidateError(UINT nCtrlID, BOOL /*bSave*/, _XData& /*data*/) {
// Override to display an error message
::MessageBeep((UINT)-1);
T* pT = static_cast(this);
::SetFocus(pT->GetDlgItem(nCtrlID));
}
Как видим, эти функции издают звуковой сигнал и устанавливают фокус ввода на контрол, в котором содержится неверное значение. Вы можете изменить это поведение на любое другое. Обратите внимание на структуру _ XData, которая передаётся в функцию OnDataValidateError. Она содержит информацию об ограничении, которое было нарушено. Вот как описана эта структура в файле atlddx.h .
// Helpers for validation error reporting
enum _XDataType {
ddxDataNull = 0,
ddxDataText = 1,
ddxDataInt = 2,
ddxDataFloat = 3,
ddxDataDouble = 4
};
struct _XTextData {
int nLength;
int nMaxLength;
};
struct _XIntData {
long nVal;
long nMin;
long nMax;
};
struct _XFloatData {
double nVal;
double nMin;
double nMax;
};
struct _XData {
_XDataType nDataType;
union {
_XTextData textData;
_XIntData intData;
_XFloatData floatData;
};
};
Соответственно, в функции OnDataValidateErrorнужно проанализировать значение поля nDataTypeи выбрать в зависимости от него структуру textData, intDataили floatData, которая и будет содержать информацию о нарушенном ограничении.
ПРИМЕЧАНИЕ
MFC не позволяет повлиять на отображение ошибки валидации. Если вы используете функции DDV_*, вы всегда будете получать сообщение об ошибке валидации в виде message box'а. Изменить это поведение нельзя, можно только отказаться от DDV_* и использовать для валидации функции "собственного изготовления".
Теперь посмотрим, как механизм DDX выглядит "изнутри". К счастью, в его реализации нет ничего сложного. От класса CWinDataExchange<>ваш класс наследует функции DDX_Text, DDX_Int, DDX_Float, DDX_Control, DDX_Checkи DDX_Radio, которые и выполняют собственно обмен данными. Некоторые из них перегружены, а DDX_Intи вовсе оформлена как шаблон, что позволяет работать с самыми разными целыми типами.
После обработки препроцессором карта DDX превращается в функцию DoDataExchange. Макросы BEGIN_DDX_MAPи END_DDX_MAPсоздают пролог и эпилог этой функции. "Заготовка" карты:
BEGIN_DDX_MAP(CMyDialog)
// Другие макросы карты DDX
END_DDX_MAP()
превращается в:
BOOL DoDataExchange(BOOL bSaveAndValidate = FALSE, UINT nCtlID = (UINT)-1) {
bSaveAndValidate;
nCtlID;
// Другие макросы карты DDX
return TRUE;
}
Что касается остальных макросов DDX_*, то все они реализованы примерно одинаково. Сначала они сравнивают свой идентификатор контрола nIDс идентификатором nCtlID, который был передан в функцию DoDataExchange. Если идентификаторы равны или nCtlIDравен -1, макрос вызывает соответствующую функцию DDX_*. Далее проверяется возвращаемое значение, и если оно равно FALSE, обмен данными прекращается. Рассмотрим для примера макросы DDX_TEXTи DDX_TEXT_LEN. Обратите внимание, что они используют одну и ту же функцию DDX_Text, но передают ей разные параметры.
#define DDX_TEXT(nID, var) \
if (nCtlID == (UINT)-1 || nCtlID == nID) \
{ \
if (!DDX_Text(nID, var, sizeof(var), bSaveAndValidate)) \
return FALSE; \
}
#define DDX_TEXT_LEN(nID, var, len) \
if (nCtlID == (UINT)-1 || nCtlID == nID) \
Интервал:
Закладка: