Діалоги. Знайомство з елементами керування - MFC
Діалоги та елементи управління - дуже велика тема. Наприклад, для повного висвітлення теми елементів управління знадобилася ціла книга. Тому в даних методичних вказівках ми розглянемо спочатку основи, а потім лише елементи управління, що найбільш широко використовуються. Це стане добрим фундаментом на шляху до поглибленого вивчення MFC.
Діалог (діалогове вікно) є спеціальним видом вікна, які призначені для взаємодії з користувачем. Зазвичай вони використовуються для зміни налаштувань програми та введення інформації. Діалоги використовують дуже часто. Наприклад, практично всі вікна параметрів програми Microsoft Word є діалогами.
Взаємодія між діалогом та користувачем Взаємодія між діалогом та користувачем здійснюється за допомогою елементів керування. Це особливий тип вікон для введення чи виведення. Елемент управління належить вікну-власнику, у разі - діалогу. Всі версії Windows підтримують певний набір стандартних елементів керування, до яких належать кнопки, контрольні перемикачі, селекторні кнопки, списки, поля введення, комбіновані списки, смуги прокручування та статичні елементи. Вам мають бути знайомі всі ці елементи. Розглянемо коротко кожен із них:
- Звичайна кнопка (push button) - це кнопка, яку користувач "натискає" мишею або Enter, перемістивши попередньо на неї фокус введення.
- Контрольний перемикач (check box) може бути вибраним, або ні. Якщо у діалозі є кілька контрольних перемикачів, можуть бути обрані одночасно кілька їх.
- Радіокнопка (radio button) - це майже те саме, що і контрольний перемикач. Тільки за наявності кількох кнопок у групі може бути обрано лише одну.
- Список (list box) містить набір рядків, з яких можна вибрати один або кілька. Широко використовується для відображення імен файлів.
- Поле введення (edit box) - це елемент, що дозволяє ввести текстовий рядок.
- Комбінований список (combo box) є список з рядком введення.
- Статичний елемент (static control) призначений виведення тексту чи графіки, але з призначений для введення.
Елементи управління здатні як генерувати повідомлення у відповідь на дії користувача, так і отримувати їх від програми. У разі повідомлення є, фактично, командами, куди елемент управління має відреагувати.
Класи MFC для елементів керування
MFC містить класи для всіх стандартних елементів керування. Ці класи описують самі елементи, і навіть містять функції до роботи з ними. Їх називають класами управління. Вони породжуються від класу CWnd. Таким чином, всі вони мають характеристики вікна. Нижче наведено основні класи управління:
Модальні та немодальні діалоги
Є два типи діалогів: модальні та немодальні. Найбільш поширені перші. У разі модальних діалогів, при активізації діалогу основне вікно програми стає пасивним і перестає реагувати на дії користувача, доки він не закриє діалог. У разі немодальних діалогів діалог існує незалежно від інших вікон, і основне вікно також може бути активізовано. Програмувати немодальні діалоги трохи складніше. Ми розглянемо обидва типи діалогів.
Діалоги як ресурси
Як згадувалося вище, діалоги не створюються програмно. Натомість, за потреби з ресурсів завантажуються описи діалогів, і Windows за цим описом формує вікно і розміщує на ньому всеелементи керування.
Клас CDialog
У MFC всі діалоги є екземплярами або класу CDialog, або породжених від нього класів. Лише найпростіші діалоги використовують безпосередньо клас CDialog. У випадку, необхідно визначати власний клас. Клас CDialog має конструктори з такими прототипами:
Параметр ResourceName або ResourceID визначає ідентифікатор діалогу в ресурсах, рядковий чи числовий. Параметр Owner – це покажчик на вікно-власник, якщо дорівнює 0, то власником буде головне вікно програми. Остання форма конструктора варта створення немодальних діалогів, про які буде сказано надалі.
Обробка повідомлень від діалогів
Усі діалоги є різновидом вікон. Тому для них використовується такий самий механізм повідомлень, як і для головного вікна. Для кожного діалогу організується власна черга повідомлень, так само точно, як для головного вікна.
Щоразу, коли елемент управління діалогу активізується, діалогу надсилається повідомлення WM_COMMAND. Із цим повідомленням передається ідентифікатор елемента керування. Для обробки повідомлень до карти повідомлень діалогу потрібно помістити макрос ON_COMMAND(). Багато елементів управління генерують також ідентифікаційний код, який дозволяє визначити, яка дія була зроблена з елементом управління. У багатьох випадках з цього коду вибирається той чи інший обробник. Як буде показано далі, MFC є механізм, подібний макросу ON_COMMAND(), за допомогою якого можна пов'язувати ідентифікаційні коди з обробниками.
Виклик діалогу
Після того, як створено об'єкт класу діалогу, необхідно викликати член-функцію DoModal(). Результатом буде модальне відображення діалогу. Прототип функції наступний:
Функція повертає код завершення, що генерується діалогом при закритті, або -1, якщо вікно не може відображатися. Якщо під час відображення діалогу виникла помилка, повертається IDABORT. Функція не завершується, доки діалог не буде закритий.
Закриття діалогу
За замовчуванням діалог закривається під час отримання повідомлення з ідентифікатором або IDOK, або IDCANCEL. Вони зумовлені і зазвичай пов'язані з кнопками підтвердження та скасування. Клас CDialog містить вбудовані обробники цих двох випадків, OnOK() і OnCancel(). Їх не потрібно включати до черги повідомлень діалогу. Але їх можна перевизначити, що дозволяє програмісту керувати закриттям діалогу. Для програмного закриття діалогу потрібно викликати член-функцію з прототипом:
Параметр визначатиме значення, яке поверне функція DoModal(). Зазвичай повертаються IDOK або IDCANCEL, інші значення використовуються рідко.
Приклад програми з діалоговим вікном
Нижче наведено вихідні тексти прикладу програми з діалогом. Діалог вибирається за допомогою меню. Він має три елементи управління - кнопки "Red", "Green" та "Cancel". Також перевизначено функцію OnCancel(), що дозволяє при спробі закриття діалогу вивести вікно з підтвердженням. Діалог закривається програмно з поверненням коду завершення 7, який потім повертається функцією DoModal() і відображається у вікні. Це зроблено лише демонстрації, реально ж зазвичай повертається IDCANCEL. Діалог створювався візуально серед Visual C++. Тут наводиться файл з ідентифікаторами, згенерований середовищем. Надалі цей файл наводитись не буде, тому що, взагалі кажучи, він не призначений для читання людиною. Оскільки всі ідентифікатори в прикладах мають осмислені імена, то завантаживши проект у середу IDE, Ви зможете відразу дізнатися, якіідентифікатори яких елементів управління відповідають.
Ініціалізація діалогу
Часто різні змінні та елементи керування, пов'язані з діалогом, повинні бути ініціалізовані до того, як буде відображено діалог. Щоб дозволити діалогу виконати подібні дії, Windows автоматично надсилає йому повідомлення WM_INITDIALOG у момент створення. При отриманні такого повідомлення MFC автоматично викликає член-функцію OnInitDialog(), яка є стандартним обробником, визначеним у класі CDialog. Ця функція повинна перевизначатися в програмі, якщо потрібне виконання різних ініціалізаційних дій. Прототип функції такий:
Ця функція викликається до відображення діалогу. Вона повинна повертати TRUE, щоб Windows могла передати фокус введення (тобто зробити активним) на перший елемент керування у вікні.
Першою дією перевизначеної функції повинен бути виклик функції CDialog::OnInitDialog().
Надалі ми будемо використовувати цю функцію у прикладах.
Список є одним із найпоширеніших елементів управління. У MFC робота зі списком здійснюється через клас CListBox.
Основи роботи зі списками
Списки є елементами управління, що вимагають двосторонньої взаємодії між ними та програмою. Тобто список може як надсилати, так і приймати повідомлення. Зокрема, повідомлення надсилаються списку за його ініціалізації. Сюди входить передача набору рядків, які відображаються у вікні списку (за замовчуванням список створюється порожнім). Коли список ініціалізований, він надсилає повідомлення про дії, зроблені з ним користувачем.
Прийом ідентифікаційних кодів списку
Список може генерувати повідомлення різних типів. Наприклад, повідомлення надсилаються приподвійному клацанні на елементі списку, при втраті списком фокусу введення та при виборі іншого елемента зі списку. Кожна подія описується ідентифікаційним кодом. Цей код є частиною WM_COMMAND повідомлення. Деякі інші елементи використовують ідентифікаційні коди.
Єдиний код, який ми скористаємося, називається LBN_DBLCLK. Він надсилається, коли користувач виконує подвійне клацання на елементі списку. (При визначенні списку в ресурсах має бути встановлена опція Notify, щоб він міг генерувати це повідомлення.) Коли вибір зроблено, необхідно запросити список, щоб дізнатися, який елемент вибрано.
Для обробки повідомлення LBN_DBLCLK необхідно помістити його оброблювач у карту повідомлень. Але це не буде макрос ON_COMMAND(). Натомість у цьому випадку використовуються спеціальні макрокоманди. Для нашого повідомлення це буде ON_LBN_DBLCLK(). Вона має такий вигляд:
Багато повідомлень обробляються подібним чином. Назви всіх макросів таких повідомлень починаються з префікса ON_LBN_.
Надсилання повідомлень списку
У традиційних програмах Windows повідомлення надсилаються елементам керування за допомогою API-функцій, наприклад SendDlgItemMessage(). Але в програмах MFC для цих цілей застосовуються відповідні функції-члени. Вони автоматично надсилають потрібне повідомлення елементу керування. У цьому полягає перевага MFC проти традиційним методом програмування.
Списку можна надіслати кілька різних повідомлень. Для кожного класу CListBox містить окрему член-функцію. Наприклад, розглянемо такі функції:
Отримання вказівника на список
Функції CListBox працюють із об'єктами CListBox. Отже, необхідно отримати вказівник на об'єкт списку, що робиться за допомогою функціїGetDlgItem(), яка є членом класу CWnd:
Ця функція повертає покажчик на об'єкт, ідентифікатор якого передано як параметр. Якщо такий об'єкт не існує, то повертається 0. Необхідно розуміти, що покажчик, що повертається функцією, є тимчасовим. Він дійсний лише в межах поточного оброблювача.
Значення, повернене функцією, має бути наведено типу покажчика на конкретний клас управління. Наприклад, у нашому випадку це тип CListBox*.
Ініціалізація списку
Оскільки список за замовчуванням створюється порожнім, він повинен ініціалізуватися кожного разу, коли відображається діалог. Для цього необхідно перевизначити функцію OnInitDialog(), в якій до списку додавалися рядки. Якщо при додаванні елементів до списку їх кількість перевищить те, що міститься у вікні списку, то у цьому вікні автоматично з'явиться вертикальна смуга прокручування.
Приклад програми
Поле введення
Це останній елемент управління, який ми розглянемо як вступ до діалогів і елементів управління. Поля введення використовуються дуже широко, тому що дають можливість ввести рядок на власний розсуд. Навіть знаючи, як створювати лише поля введення та списки, вже можна писати корисні програми.
Поля введення приймають багато повідомлень і можуть генерувати кілька типів повідомлень. Однак, зазвичай відповідати на більшість з них немає необхідності. Як Ви скоро переконаєтеся, поля введення самостійно виконують більшість функцій редагування. Для цього не потрібна взаємодія з програмою. Потрібно лише вирішити, коли вимагати вміст поля введення.
Для отримання поточного вмісту поля вода, що складається з одного рядка, використовується функція GetWindowText(). Її прототип такий:
У момент створення поле введенняє порожнім. Для ініціалізації його вмістом використовується ще одна функція-член класу CWnd – SetWindowText(). Вона відображає рядок в елементі керування, який викликав цю функцію. Ось її прототип:
Приклад програми з полем уведення
Немодальні діалоги
Немодальні діалоги отримують повідомлення паралельно з основним вікном програми. Тобто, як мінімум, два вікна будуть одночасно активними. Тому робота з немодальними діалогами потребує трохи більше зусиль, мають бути виконані додаткові операції.
Для створення немодального діалогу необхідно виконати дві дії. По-перше, потрібно створити "порожній" об'єкт діалогу, тобто не пов'язаний із шаблоном із ресурсів. Прив'язування до ресурсів здійснюється через функцію Create(). Розглянемо цей процес докладніше.
Для створення об'єкта немодального діалогу потрібно використовувати конструктор CDialog: CDialog () без параметрів. Він оголошений як protected-член класу. Це означає, що може бути викликаний лише зсередини член-функції породженого класу. Це зроблено, щоб програміст обов'язково визначав свій породжений клас для немодального діалогу, і визначав у ньому додаткові операції для немодального діалогу.
Коли екземпляр створено, він прив'язується до ресурсів за допомогою функцій:
Перший параметр визначає ідентифікатор діалогу ресурсів. Другий параметр, як завжди, визначає вікно-власник діалогу.
Необхідно пам'ятати, що об'єкт немодального діалогу повинен існувати протягом усього часу використання діалогу. Функція Create() відображає вікно, після чого негайно завершується. А об'єкт вікна має існувати.
Для закриття немодального діалогу необхідно використовувати функцію DestroyWindow(). Це означає, що функції OnCancel()та/або OnOK() мають бути перевизначені.