Вернуться наверх
aco.ifmo.ru photonic
вернуться в оглавление предыдущая глава предыдущий параграф следующий параграф следующая глава


3.3. Механизм обмена данными между элементами управления и программой DDX/DDV.

Механизм обмена данными диалога (dialog data exchange, DDX) представляет собой простой способ инициализации элементов управления диалогового окна и получения вводимых пользователем данных. Механизм проверки данных диалога ( dialog data validation, DDV ) обеспечивает простой способ контроля данных, вводимых в диалоговом окне.

Механизмы DDX и DDV реализованы в классе диалога и используют программную архитектуру, аналогичную описанной для карты сообщений. Переменные-члены класса диалога сопоставляются с элементами управления шаблона диалога, а с помощью глобальных MFC -функций выполняется обмен данными между переменными-членами и элементами управления, а также проверка данных, вводимых пользователем.

При создании класса диалога ClassWizard добавляет в него код реализации базовой архитектуры DDX/DDV. Далее посредством ClassWizard Вы сможете добавлять в класс диалога переменные, соответствующие элементам управления шаблона диалога, и определять правила простейшей проверки данных, вводимых в эти элементы.

При добавлении переменных-членов DDX ClassWizard выполняет следующие действия:

  • добавляет переменные-члены в определение класса;
  • инициализирует переменные-члены в конструкторе класса;
  • добавляет в класс DDX -функции обмена данными между DDX -переменными и элементами управления диалогового окна;
  • если для задания критериев проверки используется ClassWizard , то он добавляет в класс DDV -функции проверки, которая выполняется до сохранения данных в переменных-членах DDX .

Функции DDX и DDV - это глобальные MFC -функции, предназначенные для обмена данными между элементами управления и переменными-членами класса диалога ( DDX -функции) и для контроля вводимых данных ( DDV -функции). В MFC имеется несколько DDX -функций, соответствующих разным типам элементов управления. Наиболее часто используются следующие функции:

  • DDX_Text() - для обмена данными между полем ввода и переменной-членом типа CString и
  • DDX_Check() - для установки или передачи состояния флажка в переменную-член типа BOOL .

В MFC также имеется несколько DDV -функций, соответствующих разным способам проверки, применяемым к строковым или числовым переменным:

  • DDV_MaxChars() и
  • DDV_MinMaxInt() .

Чтобы познакомиться с полным списком этих функций, введите DDX_ или DDV_ в поле Keyword вкладки Index справочной системы Visual C++ .

Обычно переменная-член (а также DDX -функция) создается для каждого элемента управления диалогового окна, предназначенного для ввода данных или изменения его состояния. Однако контроль за данными осуществляют только в случаях, когда не допускается выход вводимых значений за границы допустимого диапазона.

В следующих упражнениях средствами ClassWizard мы добавим переменные-члены DDX и определим критерии проверки данных.

  • Добавление переменных-членов DDX средствами ClassWizard .
    1. Вернитесь к проекту.
    2. Нажмите CTRL+W , чтобы открыть ClassWizard . Щелкните вкладку Member Variables .
    3. В списке Class name выберите класс CConnectDialog .
    4. В списке Control IDs щелкните IDC_USERID .
    5. Щелкните Add Variable . Появится диалоговое окно Add Member Variable .
    6. В поле Member variable name введите m_strUserID .
    7. Убедитесь, что в списке Category установлено Value , а в поле Variable type - CString .

    8. Щелкните ОК , чтобы добавить переменную. В списке Control IDs Вы увидите выделенную строку для идентификатора IDC_USERID , в которой показаны тип и имя новой переменной. Эта переменная будет использоваться для заполнения поля User ID и для хранения текста, введенного пользователем в этом элементе управления.
    9. Введите число 15 в поле Maximum Characters , расположенное под списком Control IDs . Будет создана функция, которая контролирует превышение длины вводимого текста сверх 15 символов.

    10. Повторите описанные выше действия, чтобы создать переменную m_strPassword типа CString , связанную с элементом управления IDC_PASSWORD и ограниченную 15 символами.
    11. Добавьте переменную m_nAccess типа int , связанную с элементом управления IDC_ACCESS . Обратите внимание, что для переменной целого типа разрешается задать максимальное и минимальное значения. В поле Minimum Value введите 1, а в поле Maximum Value значение 5.

    12. Добавьте переменную m_bConnect типа BOOL , связанную с идентификатором IDC_CHECKCONTROL и предназначенную для первоначальной установки флажка в положение "установлен" ( TRUE ) или "сброшен" ( FALSE ), а также для хранения состояния, в которое флажок установит пользователь.
    13. Щелкните ОК , чтобы закрыть ClassWizard . Соберите и запустите приложение МуАрр .
    14. Выберите в меню Data команду Connect и введите имя пользователя и пароль. Посмотрите, как блокируется ввод имени пользователя, превышающего 15 символов, в соответствии с правилом проверки, заданным в пункте 9. Реализация ограничения осуществляется функцией DDV_MaxChars() , которая при инициализации элемента управления посылает ему сообщение ЕМ_LIMITTEXT . Контроль, выполняемый непосредственно при вводе, удобнее для пользователя по сравнению с проверкой введенного значения, инициируемого щелчком кнопки ОК (или кнопки Connect в данном случае).
    15. Чтобы задать обычную проверку, введите 6 в поле Access level и щелкните Connect . Функция проверки для этого поля предупредит Вас посредством сообщения в информационном окне о недопустимости введенного значения и вернет фокус ввода в элемент управления, не прошедший проверку. В реальном приложении уровень доступа следует устанавливать, выбирая нужный элемент из списка с предварительно заданным набором значений - в этом случае отпадает необходимость в проверке введенного значения.

    16. Щелкните Cancel , чтобы закрыть диалоговое окно.

Чтобы увидеть код, добавленный ClassWizard для реализации механизма DDX/DDV , откройте файл ConnectDialog.h и найдите описание новых переменных класса:

	//{{AFX_DATA(CConnectDialog)
	enum { IDD = IDD_CONNECTDIALOG };
	CString	m_strUserID;
	CString	m_strPassword;
	int  m_nAccess;
	BOOL	m_bConnect;
	//}}AFX_DATA

Как и весь код, обслуживаемый ClassWizard , эти объявления находятся внутри блока //{{AFX_ .

Найдите в файле ConnectDialog.cpp конструктор класса и код, добавленный ClassWizard для инициализации переменных по умолчанию:

	//{{AFX_DATA_INIT(CConnectDialog)
	m_strUserID = _T("");
	m_strPassword = _T("");
	m_nAccess = 0;
	m_bConnect = FALSE;
	//}}AFX_DATA_INIT

Обмен данными между элементами управления и приложением осуществляет функция CWnd::DoDataExchange() . Переопределяемая версия этой функции автоматически формируется средствами ClassWizard при создании класса, производного от CDialog . ClassWizard добавляет в нее обращения к DDX/DDV -функциям.

Функция CConnectDialog::DoDataExchange() расположена в файле ConnectDialog.cpp и на данном этапе должна выглядеть следующим образом:

	void CConnectDialog::DoDataExchange(CDataExchange* pDX)
	{
		CDialog::DoDataExchange(pDX);
		//{{AFX_DATA_MAP(CConnectDialog)
		DDX_Text(pDX, IDC_USERID, m_strUserID);
		DDV_MaxChars(pDX, m_strUserID, 15);
		DDX_Text(pDX, IDC_PASSWORD, m_strPassword);
		DDV_MaxChars(pDX, m_strPassword, 15);
		DDX_Text(pDX, IDC_ACCESS, m_nAccess);
		DDV_MinMaxInt(pDX, m_nAccess, 1, 5);
		DDX_Check(pDX, IDC_CHECKCONTROL, m_bConnect);
		//}}AFX_DATA_MAP
	}

Параметр pDX , передаваемый DDX/DDV -функциям, представляет собой объект MFC -класса CDataExchange , инкапсулирующий контекст текущего обмена данными. Переменная m_bSaveAndValidate класса CDataExchange задает направление передачи данных. Если ее значение TRUE , то данные извлекаются из элемента управления для проверки и сохранения в переменной класса диалога. В противном случае ( FALSE ) данные передаются в обратном направлении - в диалоговое окно для изменения элемента управления.

Реализация процесса обмена данными

Вызов функции DoDataExchange() осуществляется функцией CWnd::UpdateData() , в которой создается объект CDataExchange , передаваемый в качестве параметра сначала функции DoDataExchange() , а затем - DDX/DDV -функциям.

Единственный параметр функции UpdateData() типа BOOL определяет направление передачи данных. Функция CDialog::OnInitDialog() , выполняемая при создании диалогового окна, вызывает UpdateData() с параметром FALSE для передачи в элементы управления значений соответствующих переменных-членов класса диалога. Когда пользователь щелкает в диалоговом окне ОК , стандартный обработчик CDialog::OnOK() вызывает UpdateData() с параметром TRUE для выполнения проверки данных и сохранения их в переменных-членах. Схема этого процесса показана на рисунке 1.

Вызов функции CWnd::UpdateData() реализует обмен данными и их проверку в любом месте программы. В качестве примера рассмотрим приложение для просмотра изображений, в котором допускается изменять разрешение и цвет изображения, манипулируя элементами управления немодального диалогового окна. Чтобы обновить изображение сразу же после изменения значений в элементах управления нужно вызвать UpdateData() . Это позволяет сохранить новые параметры в классе диалога и сделать их доступными для функций перерисовки изображения.

  • Задание начальных значений для элементов управления диалогового окна .
    1. Вернитесь к проекту.
    2. На вкладке ClassView раскройте узел класса СМуАррАрр .
    3. Дважды щелкните значок OnDataConnect() , чтобы отредактировать эту функцию.
    4. Между объявлением объекта CConnectDialog и вызовом функции DoModal() вставьте следующие строки:
      	aCD.m_nAccess = 1;
      	aCD.m_bConnect = TRUE;
      Теперь вся функция выглядит так:
      	void CMyAppApp::OnDataConnect() 
      	{
      		CConnectDialog aCD; 
      		aCD.m_nAccess = 1; 
      		aCD.m_bConnect = TRUE;
      		aCD.DoModal();
      	}
      

    5. Соберите и запустите приложение МуАрр . В меню Data выберите команду Connect и убедитесь в том, что значения, присвоенные переменным-членам объекта диалога, отображаются в элементах управления.
  • Установка значений элементов управления диалогового окна .
    1. Вернитесь к функции OnDataConnect() .
    2. Удалите следующую строку кода:
      	aCD.DoModal();
    3. Вместо нее вставьте следующий код:
      	if (aCD.DoModal() == IDOK)
      	{
      		CString strMessage;
      		strMessage.Format("User %s logged in",   aCD.m_strUserID);
      		AfxMessageBox(strMessage);
      	}

      Значение IDOK , возвращаемое функцией DoModal() , свидетельствует, что пользователь закрыл окно, щелкнув кнопку ОК , а введенные в элементы управления данные обработаны соответствующими функциями проверки. Сами данные хранятся в переменных-членах DDX класса диалога. В данном примере значение, введенное в поле User ID , содержится в переменной CConnectDialog::m_strUserID .

    4. Соберите и запустите приложение МуАрр . В меню Data выберите команду Connect и убедитесь, что введенное в поле User ID имя пользователя отображается в информационном окне.