Категории
Самые читаемые
RUSBOOK.SU » Компьютеры и Интернет » Программирование » Программирование на Visual C++. Архив рассылки - Алекс Jenter

Программирование на Visual C++. Архив рассылки - Алекс Jenter

Читать онлайн Программирование на Visual C++. Архив рассылки - Алекс Jenter

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать
1 ... 93 94 95 96 97 98 99 100 101 ... 156
Перейти на страницу:

С набором символов Unicode связана ещё одна интересная проблема. Посмотрим на следующую карту DDX:

LPTSTR m_msg;

BEGIN_DDX_MAP(CMyDialog)

 ...

 DDX_Text(IDC_MESSAGE, m_msg, ...)

 ...

END_DDX_MAP()

Если попытаться откомпилировать этот код, задав макрос UNICODE, компилятор выдаст следующую ошибку: 'DDX_Text' : ambiguous call to overloaded function (неоднозначность при обращении к перегруженной функции). Дело в том, что в классе CWinDataExchange<> существует несколько перегруженных версий DDX_Text. Вот две из них:

// Text exchange

BOOL DDX_Text(UINT nID, LPTSTR lpstrText, int nSize, BOOL bSave, BOOL bValidate = FALSE, int nLength = 0) {

 ...

}

BOOL DDX_Text(UINT nID, BSTR& bstrText, int /*nsize*/, bool bsave, bool bvalidate = false, int nlength = 0) {

 ...

}

Если макрос UNICODE определён, LPTSTR превращается в wchar_t*, а BSTR& - в wchar_t*&. Получается неоднозначность. Чтобы решить эту проблему, можно переписать карту DDX так:

BEGIN_DDX_MAP(CMyDialog)

 ...

 DDX_Text(IDC_MESSAGE, (TCHAR * const)m_msg, ...)

 ...

END_DDX_MAP()

Поскольку в C++ константный указатель можно передать по значению, но не по ссылке, неоднозначность тем самым удаётся разрешить. В любом случае, если вы собираетесь компилировать программу с поддержкой Unicode, я советую вам использовать для обмена текстом переменные типа CString. Это избавит вас от многих проблем, подобных рассмотренным выше.

Использование DDX_CONTROL

Макрос DDX_CONTROL связывает контрол с объектом класса, порождённого от CWindowImplBaseT<>. Если вы знакомы с mfc, вы знаете, что там обычной практикой является связывание объекта класса CWnd (или его потомка) с контролом, даже если вам не нужно подключать его к карте сообщений, а просто вызвать несколько обёрток типа CWnd::GetWindowText или CListCtrl::GetItem. Это создаёт значительный, причём совершенно ненужный, перерасход ресурсов. Не используйте макрос DDX_CONTROL из wtl подобным образом. Он используется, если вам действительно необходимо заменить оконную процедуру контрола и обрабатывать его сообщения через карту сообщений.

Если же вам нужно просто использовать функции-обёртки из класса CWindow для работы с контролом, достаточно получить хэндл этого контрола с помощью GetDlgItem, а затем присвоить его объекту класса. Удобно делать это в обработчике WM_INITDIALOG. Например:

class CMyDialog : public CDialogImpl<CMyDialog>, public CWinDataExchange<CMyDialog> {

private:

 CWindow m_control;

 ...

public:

 BEGIN_MSG_MAP_EX(CMyDialog)

  MSG_WM_INITDIALOG(OnInitDialog)

  ...

 END_MSG_MAP()

 LRESULT OnInitDialog(HWND, LPARAM) {

  m_control = GetDlgItem(IDC_SOME_CONTROL);

  ...

 }

 ...

};

Ниже в этой статье мы увидим, что кроме CWindow в WTL существует целый набор классов для работы с контролами – CStatic, CButton, CEdit и т. д. Их можно использовать так же, как и CWindow в приведённом выше примере.

Использование DDX_RADIO

Макрос DDX_RADIO используется для работы сразу с целой группой переключателей. При этом переменная var, связанная с группой, содержит порядковый номер выбранного переключателя в группе (нумерация начинается с нуля). Значение -1 соответствует состоянию группы, в котором ни один из переключателей не выбран.

А что, если нам нужно связать переменную не со всей группой, а с конкретным переключателем из неё? В этом случае нужно просто воспользоваться макросом DDX_CHECK вместо DDX_RADIO.

Класс CUpdateUI<>: обновление дочерних окон в стиле WTL

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

Чтобы подключить механизм обновления дочерних контролов к вашему диалогу, добавьте в список базовых классов класс CUpdateUI<>, который описан в файле atlframe.h. Кроме этого, необходимо написать карту обновления пользовательского интерфейса (далее карта UI). Набор макросов, из которых составляется карта UI, минимален. Их всего 3 штуки. Все они описаны в таблице 2.

Макрос Описание BEGIN_UPDATE_UI_MAP(thisClass) Начало карты UI. thisClass – имя класса, в котором содержится карта. UPDATE_ELEMENT(nID, wType) Определяет, какие типы элементов пользовательского интерфейса с идентификатором nID должны обновляться. Нужные типы объединяются с помощью операции "ИЛИ" и передаются в качестве второго параметра макроса wType. WTL распознаёт следующие типы: UPDUI_MENUPOPUP (пункт всплывающего меню), UPDUI_MENUBAR (пункт полоски меню), UPDUI_CHILDWINDOW (дочернее окно, контрол), UPDUI_TOOLBAR (кнопка на панели инструментов) и UPDUI_STATUSBAR (панель на строке состояния). В этой статье мы сосредоточимся на контролах, а об остальных элементах поговорим, когда доберёмся до окон-рамок. END_UPDATE_UI_MAP() Этот макрос завершает карту UI. Не имеет параметров.

После того, как карта UI добавлена в класс, остаётся один завершающий штрих. Вы должны зарегистрировать все контейнеры элементов пользовательского интерфейса, которые нужно обновлять. В случае с контролами в качестве контейнера выступает сам диалог. В случае с меню это окно, содержащее меню. И так далее. Для каждого контейнера существует своя функция регистрации: UIAddMenuBar для меню, UIAddToolBar для панелей иснтрументов, UIAddStatusBar для строк состояния и UIAddChildWindowContainer для контейнеров дочерних окон. Все перечисленные функции принимают хэндл окна-контейнера и позвращают BOOL, сигнализирующий об успехе или неуспехе регистрации. В случае с диалогом регистрировать контейнер удобно в обработчике сообщения WM_INITDIALOG.

Итак, инициализация закончена. Теперь мы можем изменять состояния контролов, идентификаторы которых включены в карту UI. Для этого используется ещё один набор функций с префиксом UI. Все они перечислены в таблице 3.

Функция Описание BOOL UIEnable(int nID, BOOL bEnable, BOOL bForceUpdate = FALSE) Изменяет состояние доступности элементов с идентификатором nID в соответствии со значением bEnable. Флаг принудительного обновления bForceUpdate задаётся, когда нужно фактически обновить элемент, даже если его текущее состояние соответствует желаемому и менять ничего не надо. Поскольку все функции используют этот флаг одинаково, я больше не буду на нём останавливаться. BOOL UISetCheck(int nID, int nCheck, BOOL bForceUpdate = FALSE) Изменяет состояние флага "checked" элементов с идентификатором nID в соответствии со значением nCheck. Из контролов эту функцию имеет смысл применять только к кнопкам, так как другие контролы не имеют такого флага. nCheck может принимать одно из трёх значений: 0, если кнопка "отжата", 1, если нажата и 2, если она находится в "третьем состоянии" (кнопка активна, но отрисовывается серым цветом). Третье состояние имеется только у конпок со стилями BS_3STATE или BS_AUTO3STATE. BOOL UISetRadio(int nID, BOOL bRadio, BOOL bForceUpdate = FALSE) Изменяет состояние флага "radio" элементов с идентификатором nID в соответствии со значением nRadio. Для контролов эта функция работает аналогично предыдущей. BOOL UISetText(int nID, LPCTSTR lpstrText, BOOL bForceUpdate = FALSE) Изменяет текст элементов с идентификатором nID на заданный в параметре lpstrText. BOOL UISetState(int nID, DWORD dwState) Эта функция позволяет изменить сразу несколько флагов, связанных с элементами nID. Эти флаги объединяются операцией "ИЛИ" и передаются в качестве параметра dwState. Можно использовать флаги UPDUI_DISABLED, UPDUI_CHECKED, UPDUI_CHECKED2 (этот флаг соответствует "третьему состоянию" кнопки), UPDUI_RADIO и UPDUI_DEFAULT. Замечу, что флаг UPDUI_DEFAULT можно менять, только используя функцию UISetState. Специальной функции для его изменения нет. Этот флаг позволяет сделать элемент используемым по умолчанию. Обратите внимание, что функция UISetState не использует флаг bForceUpdate и всегда обновляет элемент, вне зависимости от его текущего состояния. DWORD UIGetState(int nID) Функция, обратная предыдущей. Возвращает набор флагов, характеризующих состояние элемента.

Функции, которые мы только что рассмотрели, не изменяют фактическое состояние элементов. Они только записывают новые значения во внутренние структуры класса CUpdateUI<>. Чтобы внесённые изменения вступили в силу, нужно вызвать специальную функцию. Для каждого типа контейнеров существует своя функция: UIUpdateMenuBar для меню, UIUpdateToolBar для панели инструментов, UIUpdateStatusBar для строки состояния и UIUpdateChildWindows для контейнера дочерних окон. Каждая из этих функций принимает флаг bForceUpdate. Используйте его, чтобы принудительно обновить все элементы, прописанные в карте UI.

1 ... 93 94 95 96 97 98 99 100 101 ... 156
Перейти на страницу:
На этой странице вы можете бесплатно скачать Программирование на Visual C++. Архив рассылки - Алекс Jenter торрент бесплатно.
Комментарии
Открыть боковую панель
Комментарии
Сергій
Сергій 25.01.2024 - 17:17
"Убийство миссис Спэнлоу" от Агаты Кристи – это великолепный детектив, который завораживает с первой страницы и держит в напряжении до последнего момента. Кристи, как всегда, мастерски строит