![]() |
|||||
![]() ![]() |
|||||
![]() |
![]() |
![]() |
![]() |
![]() |
|
|
3.4. Особенности использования элементов управления.3.4.1. Кнопка (Button).Кнопка - графический объект, который при нажатии на нее запускает какую-либо команду. При нажатии графическое изображение кнопки обычно "оживляется", показывая как бы действительное нажатие кнопки клавиатуры. Основные методы класса CButton, который используется для создания кнопок различного вида.
3.4.2. Флажок (Check Box).Контрольный переключатель ("флажок") - это элемент управления, предназначенный для установки или снятия определенной опции. Он состоит из маленького прямоугольного поля, в котором может стоять метка выбора. Кроме того, с переключателем связано текстовое поле с описанием предоставляемой переключателем опции. Если в переключателе стоит метка выбора, то говорится, что он выбран (установлен). Контрольные переключатели в MFC описываются с помощью класса CButton (так как контрольный переключатель - разновидность кнопки). Контрольные переключатели могут быть автоматическими и программными. Автоматический переключатель сам меняет свое состояние при щелчке мышью. Программный же этого не делает, а подразумевается, что сообщение о щелчке будет обработано в программе, и она изменит состояние переключателя. На практике почти всегда используются автоматические переключатели. Сообщения контрольного переключателяКаждый раз, когда пользователь щелкает мышью на контрольном переключателе (или нажимает клавишу Spacebar, когда фокус ввода находится на переключателе), диалогу посылается сообщение WM_COMMAND с идентификационным кодом BN_CLICKED. Это сообщение обрабатывается с помощью макроса ON_BN_CLICKED(). При работе с автоматическими переключателями отвечать на это сообщение нет необходимости. Но при работе с программными переключателями, чтобы изменять их состояние, необходимо отвечать на это сообщение. Для этого нужно поместить макрос в карту сообщений и написать обработчик. Установка и чтение состояния контрольного переключателяЧтобы установить контрольный переключатель в заданное состояние, нужно использовать функцию SetCheck() c прототипом: void CButton::SetCheck(int Status);Параметр определяет требуемое состояние: если он равен 1, то переключатель устанавливается, если 0 - сбрасывается. По умолчанию при первом вызове диалога переключатель будет сброшен. Автоматический переключатель также может быть установлен в требуемое состояние этой функцией. Текущее состояние переключателя можно определить с помощью функции GetCheck(): int CButton::GetCheck() const;Функция возвращает 1, если переключатель установлен, и 0 в противном случае. Инициализация контрольных переключателейПри вызове диалога переключатели сброшены. Но обычно они должны устанавливаться в предыдущее состояние при каждом вызове диалога. Поэтому их необходимо инициализировать. Для этого нужно переопределить функцию OnInitDialog(), в которой использовать функкцию SetCheck() для установки начальных состояний.
3.4.3. Переключатель (Radio Button).Переключатели ("Радиокнопки") очень похожи на контрольные переключатели. Только их работа организована таким образом, что из группы кнопок может быть установлена только одна. При установке другой кнопки предыдущая сбрасывается. Радиокнопки также бывают программные и автоматические; но так как управлять радиокнопками сложно, то сейчас почти всегда используются автоматические. Мы рассмотрим только автоматические радиокнопки. Радиокнопки объединяются в группы. В одном диалоге может быть несколько групп. Для первой кнопки каждой группы в ресурсном редакторе нужно установить опцию Group, а для других кнопок группы она должна быть сброшена. Кнопки нумеруются в порядке значений их идентификаторов (то есть в порядке их создания в ресурсном редакторе). Если в диалоге все радиокнопки образуют одну группу, то опцию Group можно не устанавливать. Радиокнопки управляются с помощью класса CButton. Также, как для контрольных переключателей, состояние радиокнопок можно изменять с помощью функции SetCheck() и читать с помощью функции GetCheck(). При создании диалога все радиокнопки сброшены. Таким образом, в функции OnInitDialog() нужно установить начальное состояние программно. Хотя из программы можно установить сразу несколько радиокнопок или сбросить все, нормальный стиль программирования под Windows предполагает, что всегда будет установлена одна и только одна радиокнопка. Таков принятый стиль.
3.4.4. Поле для ввода (Edit Box).Поля ввода используются очень широко, так как дают возможность ввести строку по своему усмотрению. Даже зная, как создавать только поля ввода и списки, уже можно писать полезные программы. Поля ввода принимают многие сообщения и сами могут генерировать несколько типов сообщений. Однако обычно отвечать на большинство из них нет необходимости. Как Вы скоро убедитесь, поля ввода самостоятельно выполняют большинство функций редактирования. Для этого не требуется взаимодействия с программой. Нужно только решить, когда затребовать содержимое поля ввода. Для получения текущего содержимого поля вода, состоящего из одной строки, используется функция GetWindowText(). Ее прототип таков: int CWnd::GetWindowText(LPSTR StringVariable, int MaxStringLen) const;В результате ее выполнения содержимое поля ввода будет скопировано в строку по адресу StringVariable. Эта функция позволяет получить текст, связанный с любым окном или элементом управления. Применительно к обычному окну функция получает заголовок окна. В момент создания поле ввода является пустым. Для инициализации его содержимым используется еще одна функция-член класса CWnd - SetWindowText(). Она отображает строку в элементе управления, который вызвал эту функцию. Вот ее прототип: void CWnd::SetWindowText(LPCSTR String);
3.4.5. Подпись (Static Text).Подпись (статический текст) - это строка символов, обычно используемых для обозначения других элементов управления в диалоговом или в простом окне. Статический текст считается управляющим элементом окна, однако пользователь не может им управлять.
3.4.6. Рамка (Group Box).Часто флажоки и радио-кнопки размещаются на групповой панели, в которой кнопки организованы в логические группы. С самой рамкой пользователь работать не может.
3.4.7. Список (List Box).Список - это прямоугольник, содержащий ряд выбираемых пунктов. Этими пунктами обычно являются тексты, но ими также могут быть растровые изображения и другие объекты. В зависимости от флагов типа списка пользователь может выбрать один или несколько объектов в списке. Список является одним из наиболее распространенных элементов управления. В MFC работа со списком осуществляется через класс CListBox. Основы работы со спискамиСписки являются элементами управления, требующими двустороннего взаимодействия между ними и программой. То есть список может как посылать, так и принимать сообщения. В частности, сообщения посылаются списку при его инициализации. Сюда входит передача набора строк, которые будут отображены в окне списка (по умолчанию список создается пустым). Когда список инициализирован, он посылает сообщения о действиях, произведенных с ним пользователем. Прием идентификационных кодов спискаСписок может генерировать сообщения различных типов. Например, сообщения посылаются при двойном щелчке на элементе списка, при потере списком фокуса ввода и при выборе другого элемента из списка. Каждое такое событие описывается идентификационным кодом. Этот код является частью сообщения WM_COMMAND. Некоторые другие элементы также используют идентификационные коды. Единственный код, которым мы воспользуемся, называется LBN_DBLCLK. Он посылается, когда пользователь выполняет двойной щелчок на элементе списка. (При определении списка в ресурсах должна быть установлена опция Notify, чтобы он мог генерировать это сообщение.) Когда выбор произведен, необходимо запросить список, чтобы узнать о том, какой элемент выбран. Для обработки сообщения LBN_DBLCLK необходимо поместить его обработчик в карту сообщений. Но это будет не макрос ON_COMMAND(). Вместо этого в данном случае используются специальные макрокоманды. Для нашего сообщения это будет ON_LBN_DBLCLK(). Она имеет такой вид: ON_LBN_DBLCLK(ИдентификаторСписка, ИмяОбработчика)Многие сообщения обрабатываются подобным образом. Названия всех макросов для таких сообщений начинаются с префикса ON_LBN_. Передача сообщений спискуВ традиционных Windows-программах сообщения посылаются элементам управления с помощью API-функций, например SendDlgItemMessage(). Но в программах на MFC для этих целей применяются соответствующие функции-члены. Они автоматически посылают нужное сообщение элементу управления. В этом заключается преимущество MFC по сравнению с традиционным методом программирования. Списку может быть послано несколько разных сообщений. Для каждого класс CListBox содержит отдельную член-функцию. Например, рассмотрим следующие функции: int CListBox::AddString(LPCSTR StringToAdd); int CListBox::GetCurSel() const; int CListBox::GetText(int Index, LPCSTR StringVariable);Функция AddString() вставляет указанную строку в список. По умолчанию она вставляется в конец списка. Начало списка имеет индекс 0. Функция GetCurSel() возвращает индекс текущего выделенного элемента. Если ни один элемент не выбран, возвращает LB_ERR. Функция GetText() получает строку, связанную с указанным индексом. Строка копируется в символьный массив по адресу StringVariable. Получение указателя на списокФункции CListBox работают с объектами CListBox. Значит, необходимо получить указатель на объект списка, что делается с помощью функции GetDlgItem(), являющейся членом класса CWnd: СWnd *CWnd::GetDlgItem(int ItemIdentifier) const;Эта функция возвращает указатель на объект, чей идентификатор передан как параметр. Если такой объект не существует, то возвращается 0. Необходимо понимать, что указатель, возвращаемый функцией, является временным. Он действителен только в пределах текущего обработчика. Значение, возвращенное функцией, должно быть приведено к типу указателя на конкретный класс управления. Например, в нашем случае это тип CListBox*. Инициализация спискаПосколькlу по умолчанию список создается пустым, он должен инициализироваться каждый раз, когда отображается диалог. Для этого необходимо переопределить функцию OnInitDialog(), в которой в список добавлялись бы строки. Если при добавлении элементов в список их число превысит то, которое помещается в окне списка, то в этом окне автоматически появится вертикальная полоса прокрутки.
3.4.8. Комбинированный список (Combo Box).Комбинированный список аналогичен списку, однако в него входит также и область ввода, в которой пользователь может набрать текст выбранного пункта.
3.4.9. Закладки (Tabs).Tab control - это мощное средство для решению многих проблем в интерфейсе приложений. Оно позволят существенно увеличить скорость работы вашего приложения, разбить на "части" диалог в удобной для пользователя форме. В MFC есть встроенный класс по работе с Tab control - класс CTabCtrl. Для практики напишем программу, которая будет использовать класс CTabCtrl и в которой будет три "закладки" - диалога. Шаги создания проекта:
Для начала сделайте первые три пункта, создайте переменную m_ctrTab класса CTabCtrl. После этого в функцие BOOL CTab_controlDlg::OnInitDialog() добавте следующее: ... TC_ITEM TabItem; TabItem.mask = TCIF_TEXT; TabItem.pszText = "Закладка1"; m_ctrTab.InsertItem( 0, &TabItem ); TabItem.pszText = "Закладка2"; m_ctrTab.InsertItem( 1, &TabItem ); TabItem.pszText = "Закладка3"; m_ctrTab.InsertItem( 2, &TabItem ); ... Это код инициализации Tab Control, мы создаём три закладки. Теперь нам надо, чтобы при нажатие на любую закладку, на экране появлялось то, что нам нужно. Самый простой вариант - это использовать на каждую закладку по диалогу - и потом просто в области Tab Control'а - выводить нужный диалог, в зависимости от текущей закладки. Сделаем это. Добавим три диалога в редакторе ресурсов и создадим каждому из них по классу - наследнику от CDialog. Назовем эти классы CPage1, CPage2 и CPage3( файлы Page1.cpp(h), Page2.cpp(h), Page3.cpp(h) ) . В свойствах этих трёх диалогов поставте Style как "Child" и Border как "none" - это очень важно, а в самих диалогах создайте какие либо элементы ( например, типа Static Text ), чтобы было видно отличие. Напишите эти три строчки в начале файла tab_controlDlg.cpp #include "Page1.h" #include "Page2.h" #include "Page3.h" Продолжим в OnInitDialog: Надо последовательно создать все страницы, причём указатели на них хранятся в самом m_ctrTab !!! В этом примере мы ипользовали lParam структуры TCITEM как хранилище указателя. Теперь переменные pPage1, pPage2 и pPage3 больше не нужны - указатели хранятся в надежном месте! Для каждой страницы вызывается метод ShowWindow() - для отображения первой, и скрытия остальных страниц. ... CPage1* pPage1; pPage1 = new CPage1; TabItem.mask = TCIF_PARAM; TabItem.lParam = (LPARAM)pPage1; m_ctrTab.SetItem(0, &TabItem); VERIFY(pPage1->Create(CPage1::IDD, &m_ctrTab)); pPage1->SetWindowPos(NULL, 10, 30, 0, 0, SWP_NOSIZE | SWP_NOZORDER); pPage1->ShowWindow(SW_SHOW); CPage2* pPage2; pPage2 = new CPage2; TabItem.mask = TCIF_PARAM; TabItem.lParam = (LPARAM)pPage2; m_ctrTab.SetItem(1, &TabItem); VERIFY(pPage1->Create(CPage2::IDD, &m_ctrTab)); pPage2->SetWindowPos(NULL, 10, 30, 0, 0, SWP_NOSIZE | SWP_NOZORDER); pPage2->ShowWindow(SW_HIDE); CPage3* pPage3; pPage3 = new CPage3; TabItem.mask = TCIF_PARAM; TabItem.lParam = (LPARAM)pPage3; m_ctrTab.SetItem(2, &TabItem); VERIFY(pPage1->Create(CPage3::IDD, &m_ctrTab)); pPage3->SetWindowPos(NULL, 10, 30, 0, 0, SWP_NOSIZE | SWP_NOZORDER); pPage3->ShowWindow(SW_HIDE); ... Теперь добавим код по отображению текущей страницы и сокрытию предыдущей. Для этого добавим обработчики сообщений TCN_SELCHANGE и TCN_SELCHANGING: void CTab_controlDlg::OnSelchangingTab(NMHDR* pNMHDR, LRESULT* pResult) { // TODO: Add your control notification handler code here int nTab = m_ctrTab.GetCurSel(); TC_ITEM tci; tci.mask = TCIF_PARAM; m_ctrTab.GetItem(nTab, &tci); ASSERT(tci.lParam); CWnd* pWnd = (CWnd *)tci.lParam; pWnd->ShowWindow(SW_HIDE); *pResult = 0; } void CTab_controlDlg::OnSelchangingTab(NMHDR* pNMHDR, LRESULT* pResult) { int nTab = m_ctrTab.GetCurSel(); TC_ITEM tci; tci.mask = TCIF_PARAM; m_ctrTab.GetItem(nTab, &tci); ASSERT(tci.lParam); CWnd* pWnd = (CWnd *)tci.lParam; pWnd->ShowWindow(SW_HIDE); *pResult = 0; } Здесь используются те самые указатели, которые мы спрятали в OnInitDialog Теперь освободим память и разрушим диалоговые окна при выходе из приложения. Добавим функцию OnDestroy: void CTab_controlDlg::OnDestroy() { CDialog::OnDestroy(); CWnd* pWnd; TC_ITEM tci; tci.mask = TCIF_PARAM; for (int i = 2; i>=0; i--) { m_ctrTab.GetItem(i, &tci); ASSERT(tci.lParam); pWnd = (CWnd *)tci.lParam; pWnd->DestroyWindow(); delete pWnd; } } Ну вот и всё, приложение готово. |