Робота з вікнами додатків

[ виправити ] текст може містити помилки, будь ласка перевіряйте перш ніж використовувати.

скачати

Повідомлення миші, робота з мишею

Окремо треба розглянути роботу з мишею. Зазвичай, коли курсор миші знаходиться над будь-яким вікном, це вікно отримує повідомлення від миші, причому зовнішній вигляд курсору миші визначений при реєстрації класу вікна - поле. HCursor структури WNDCLASS. Якщо ми хочемо використовувати мишу в нашому застосуванні, то ми повинні обробляти деякі повідомлення, що посилаються мишею.
WM_NCHITTEST 0 y & x
При переміщення миші через область, зайняту вікном, вікно отримує повідомлення WM_NCHITTEST, які використовуються для того, щоб визначити місце розташування миші - на рамці, в кутах рамки, на заголовку, у внутрішній області тощо Це повинно бути визначено при обробці даного повідомлення і повертається результат характеризує положення курсору миші. Наприклад HTCLIENT вказує, що курсор знаходиться над внутрішньою областю вікна, HTTOPLEFT - над верхнім лівим куточком рамки вікна, розміри якого можуть бути змінені і пр. Положення курсору зазначено в координатах екрану.
WM_NCMOUSEMOVE wHitTest y & x
Якщо WM_NCHITTEST визначає, що курсор знаходиться над зовнішньою областю вікна, то вікно отримує повідомлення WM_NCMOUSEMOVE; Y і X координати задані відносно екрану.
WM_NCLBUTTONDOWN wHitTest y & x
WM_NCLBUTTONUP wHitTest y & x
WM_NCRBUTTONDOWN wHitTest y & x
WM_NCRBUTTONUP wHitTest y & x
WM_NCMBUTTONDOWN wHitTest y & x
WM_NCMBUTTONUP wHitTest y & x
WM_NCLBUTTONDBLCLK wHitTest y & x
WM_NCRBUTTONDBLCLK wHitTest y & x
WM_NCMBUTTONDBLCLK wHitTest y & x
Ці повідомлення надсилаються при натисканні / відпуску відповідних кнопок миші над зовнішньою областю вікна; Положення курсору зазначено в координатах екрану, wParam вказує зону, над якою відбулося це подія.
WM_MOUSEMOVE nKeys y & x
Коли миша переміщується у внутрішній області вікна (WM_NCHITTEST повернуло HTCLIENT) то віконна процедура обробляє які повідомлення WM_MOUSEMOVE, що вказують положення миші в координатах вікна та стан деяких клавіш (ctrl, shift і три кнопки миші).
WM_LBUTTONDOWN nKeys y & x
WM_LBUTTONUP nKeys y & x
WM_RBUTTONDOWN nKeys y & x
WM_RBUTTONUP nKeys y & x
WM_MBUTTONDOWN nKeys y & x
WM_MBUTTONUP nKeys y & x
Ці повідомлення надсилаються вікна, якщо Ви натиснули одну з кнопок миші, коли курсор знаходиться над вікном. Параметр nKeys вказує стан деяких клавіш.
WM_LBUTTONDBLCLK nKeys y & x
WM_RBUTTONDBLCLK nKeys y & x
WM_MBUTTONDBLCLK nKeys y & x
Це повідомлення про двох швидких натисканнях на одну кнопку миші. Зазвичай вікно їх не отримує. Якщо Ви хочете використовувати ці повідомлення, то Ви повинні при реєстрації класу вікна вказати стиль CS_DBLCLKS.
Крім того треба мати на увазі, що перед повідомленням про подвійне натискання на кнопку Ви отримаєте повідомлення про перший (одиночному) натисненні. Тому треба так розподіляти дії між поодинокими і подвійними натисканнями, що б вони не суперечили одне одному. У самому вдалому випадку подвійне натискання виконує додаткову обробку в порівнянні з одиночним.
Ви можете легко змінювати зовнішній вигляд курсору, змінюючи його хендл у структурі класу вікна:
UINT SetClassWord (hWnd, GCW_HCURSOR, hNewCursor);
однак при цьому змінюється курсор для всіх вікон, що належать до цього класу. Якщо Ви використовуєте цей метод, то Вам треба перевіряти зміна активності вікна - при деактивації Ви повинні відновити колишній курсор, при активації - встановити необхідний. Для того, щоб отримати хендл курсору ми можемо скористатися наступними функціями:
HCURSOR LoadCursor (hInstance, lpszCursor);
HCURSOR CreateCursor (
hInstance, xHotSpot, yHotSpot, nWidth, nHeight, lpvAND, lpvXOR
);
BOOL DestroyCursor (hCursor);
Функція LoadCursor завантажує стандартний курсор або визначений Вами, CreateCursor створює новий курсор за допомогою двох масок - lpvAND і lpvXOR, які дозволяють описати чотириколірний курсор - чорний, білий, колір фону, інвертований фон. У застосуванні цієї функції є тільки один "підводний камінь" - ширина і висота створюваного курсору повинні збігатися з вимогами драйвера. Для цього їх треба попередньо дізнатися за допомогою функції
int GetSystemMetrics (SM_CXCURSOR);
int GetSystemMetrics (SM_CYCURSOR);
Функція DestroyCursor призначена для знищення курсор, який Ви завантажили з власних ресурсів або створили за допомогою CreateCursor.
Ви можете легко показати або заховати курсор за допомогою функції
int ShowCursor (bShow);
Ви можете встановити або дізнатися позицію курсору за допомогою функції
void SetCursorPos (nX, nY);
void GetCursorPos (lpPoint);
Також можна обмежити зону переміщення курсору за допомогою функції
void ClipCursor (lpRect);
Ще одна функція,
HCURSOR SetCursor (hCursor);
використовується для завдання хендла курсору, відображуваного в даний момент. Проте використовувати її треба обережно, так як курсор є ресурсом, що розділяється. Якщо Ви використовуєте цю функцію, то Ви повинні відновлювати попередній курсор перед тим, як він покине межі внутрішньої області вікна, або вікно втратить активність. Перед використанням цієї функції треба переконатися, що хендл курсору, визначений для класу вікон дорівнює 0, що б система не відновлювала його колишній вигляд при кожному переміщенні. Цю функцію зручно застосовувати тільки у випадку "захоплення" курсору.
У деяких випадках буває зручно застосовувати так званий "захоплення" курсору. "Захоплених" курсор може переміщатися по всьому вікну, але повідомлення від миші надходять тільки в те вікно, яке захопило курсор. При вікно не отримує повідомлень WM_NCHITTEST, WM_NCMOUSEMOVE і пр., а отримує повідомлення як би від внутрішньої області вікна. Звичайно, робити таке потрібно на невеликий час, наприклад для реалізації механізму "Перенести і покласти" (Drag And Drop). Тільки одне вікно може захоплювати курсор на даний час.
Для "загарбання" курсору призначені наступні функції:
HWND SetCapture (hWnd);
void ReleaseCapture (void);
Функція SetCapture повертає хендл попереднього вікна, що використовував "захоплення" в цей час, або NULL.

Різновиди вікон: дочірні, батьківські, використовувані (owned)

Поки що ми розглядали додатки, що мають тільки одне вікно - головне вікно програми. Зараз ми повинні будемо розібратися між основними типами вікон та їх взаємодії один з одним.
Вікно створюється за допомогою функції
HWND CreateWindow (
lpszClassName, lpszTitle, dwStyle,
nX, nY, nWidth, nHeight,
hwndParent, hMenu, hInstance, lpvParam
);
Цю функцію ми розглядали раніше, тому ми не будемо детально зупинятися на її аргументах. Зараз ми звернемо увагу на різні види вікон та їх взаємини.
Самий загальний вигляд вікна - перекриваються (overlapped). Таке вікно створюється, якщо вказати стиль WS_OVERLAPPED або WS_OVERLAPPEDWINDOW при створенні вікна. Ці вікна завжди мають рамку (border), заголовок (title-bar) і внутрішню область. Вікна цього стилю застосовуються в якості головних вікон програми, при цьому настійно рекомендується використовувати стиль WS_OVERLAPPEDWINDOW, який описує стандартне головне вікно програми з кнопками системного меню, максимізації та мінімізації.
Близька до перекриваються категорія вікон - спливаючі (popup) вікна, задається вказівкою стилю WS_POPUP при створенні вікна. Спливаючі вікна відрізняються від перекриваються тим, що можуть не мати заголовка (title bar). В іншому їх застосування аналогічно.
Якщо при створенні перекриваються або спливаючих вікон визначити хендл вікна - батька, то такі вікна виявляться в специфічних відносинах, званих відносинами користувача (owner) і використовується (owned) вікон.
Головна ідея таких відносин пов'язана зі спільною позиціонуванням в Z-напрямку: вікно - користувач завжди знаходиться безпосередньо під використовуваним вікном, при переміщенні одного з них в Z-напрямку, інше переміщається услід за ним. Переміщення вікон для X та Y напрямках не взаємопов'язане, використовувані вікна можуть знаходитися поза вікном-користувача. Крім того, якщо вікно-користувач стає невидимим або мінімізується, то використовувані їм вікна стають невидимими. При знищенні вікна-користувача всі використовувані вікна автоматично знищуються.
У Windows існує одна особливість - хоча при створенні використовуваного вікна оголошується хендл "батьківського" вікна, але при спробі отримати хендл батьківського вікна (наприклад, функцією GetParent), повертається NULL.
Ще одна велика категорія вікон - дочірні (child) - вікна, створюються при вказівці стилю WS_CHILD і хендла батьківського вікна (parent). Дочірні вікна обов'язково мають внутрішню область, але можуть не мати рамки і заголовка; у них не може бути меню - цей параметр функції CreateWindow задає необов'язковий ідентифікатор дочірнього вікна.
Відносини дочірніх і батьківських вікон нагадують відносини користувача і використовуваного, але мають деякі відмінності:
· Дочірні вікна можуть розміщуватися лише у внутрішній області батьківського вікна.
· Координати дочірніх вікон задаютсе щодо верхнього-лівого кута внутрішній області батьківського вікна, а не екрану.
· Дочірні вікна, що мають одного батька, називаються "сестринськими" (sibling) вікнами. Перекривають один одного сестринські вікна можуть здійснювати виведення в області перекривається вікна. Що б чітко розділити області сестринських вікон Ви повинні вказати WS_CLIPSIBLINGS при створенні дочірнього вікна.
· Якщо для дочірнього вікна заборонити отримання фокусу вводу (від миші і клавіатури), то все соощенія введення будуть спрямовані вікна-батькові.
· Батьківське вікно може здійснювати вивід поверх дочірнього вікна.
Якщо Ви хочете уникнути цього, то Вам треба вказати стиль WS_CLIPCHILDREN при створенні вікна-батька.
Знаючи хендл дочірнього вікна можна дізнатися хендл батька, якщо скористатися однією з двох функцій:
HWND GetParent (hwndChild);
HWND GetWindowWord (hwndChild, GWW_PARENT);
Розглянемо ще декілька стилів, які можна декларувати при створенні вікна. Зазвичай створене вікно може отримувати повідомлення від миші і клавіатури. Ви можете вказати стиль WS_DISABLED для того, що б це заборонити. Під час роботи Ви можете забороняти або дозволяти отримання повідомлень від клавіатури за допомогою функції
BOOL EnableWindow (hWnd, bEnable);
Другий стиль, на який треба звернути увагу - WS_VISIBLE - говорить про те, що створюється видиме вікно. Якщо його не вказати, то створене вікно буде невидимим. Пізніше вікно можна робити видимим або невидимим за допомогою функції:
BOOL ShowWindow (hWnd, SW_HIDE);
BOOL ShowWindow (hWnd, SW_SHOW);
Вікна часто створюють невидимими, якщо при їх створенні (або відразу після цього) доводиться міняти їх розмір або положення. При цьому всі операції виконують над невидимим вікном і показують тільки в його остаточному стані. Це не тільки покращує зовнішній вигляд програми, але і прискорює виконання.
Стиль вікна впливає, в основному, лише на його зовнішній вигляд, а властивості вікна визначаються віконної процедурою. Віконна процедура описується при реєстрації класу вікон, а коли створюється нове вікно ми повинні вказати ім'я класу, до якого це вікно належить. До цих пір ми самі описували і реєстрували клас вікон і потім створювали вікно, що належить цьому класу.
У Windows існує можливість використовувати один зареєстрований клас різними додатками, Ви можете самі розробити власний клас вікон, яким будуть користуватися інші програми. Зробити це досить просто - при реєстрації класу вікна Ви повинні вказати стиль класу CS_GLOBALCLASS. Після цього всі інші додатки Windows зможуть використовувати вікна цього класу. Єдине нововведення буде пов'язано з тим, що при завершенні роботи Вашого програми Ви повинні видалити оголошений клас зі списку класів Windows. Зробити це можна за допомогою функції
BOOL UnregisterClass (lpszClassName, hInstance);
Крім тих класів вікон, які були зареєстровані додатками, Windows автоматично створює кілька стандартних класів, які використовуються для створення дочірніх вікон.

Стандартні класи дочірніх вікон

Зараз ми розглянемо декілька класів дочірніх вікон, що надаються Windows. Вікна цих класів дозволяють створювати найбільш часто використовувані "керуючі елементи" - кнопки, смуги прокрутки (scroll bars), найпростіші редактори для введення тексту і пр.
Зазвичай стандартні керуючі елементи створюються зі стілtем WS_VISIBLE і, обов'язково, - WS_CHILD. Часто використовується стиль WS_BORDER. Для багатьох класів передбачений стиль, який вказує, що батьківське вікно повинно бути сповіщені про такі події дочірнього вікна, як, наприклад, отримання і втрата фокусу введення. Назва цього стилю закінчується на _NOTIFY, наприклад, LBS_NOTIFY.
Дочірні вікна, що належать до стандартних класів, обмінюються даними з батьківським вікном за такими правилами:
· Батьківське вікно при необхідності посилає рядкування вікну повідомлення з номерами, рівними або більшими WM_USER. Для кожного стандартного класу дочірніх вікон визначено свої повідомлення, на які вони реагують. Багато хто з таких повідомлень повинні повернути результат, тому часто використовується SendMessage замість PostMessage.
· Дочірнє вікно посилає батьківському вікну повідомлення WM_COMMAND, з наступним призначенням параметрів:
wPar - ідентифікатор дочірнього вікна
LOWORD (lPar) - хендл дочірнього вікна
HIWORD (lPar) - код повідомлення
код повідомлення інформує батьківське вікно про те, яка подія сталася з дочірнім вікном. Здійснення деяких сповіщень від дочірніх вікон може бути заборонена - якщо не вказувати? _NOTIFY Стиль. Для кожного класу дочірніх вікон визначено свої коди повідомлення.
· Для управління кольором дочірнього вікна батьківське може обробляти повідомлення WM_CTLCOLOR, які надсилаються усіма стандартними дочірніми вікнами їх батькам.

 


Статичні елементи

Почнемо розгляд з самого простого класу - класу статичних елементів. До статичних елементів відносяться прямокутники ("порожні" і зафарбовані), незмінний текст і ікони, намальовані в батьківському вікні. Статичні вікна не приймають повідомлень від миші і клавіатури і не можуть мати фокусу введення.
Для створення такого вікна ми повинні вказати ім'я класу "STATIC", і задати специфічний стиль, що визначає зовнішній вигляд цього елемента. Так ми можемо вказати один із стилів:
SS_BLACKRECT - чорний зафарбований прямокутник
SS_BLACKFRAME - чорний контур прямокутника
SS_GRAYRECT - сірий зафарбований прямокутник
SS_GRAYFRAME - сірий контур прямокутника
SS_WHITERECT - білий зафарбований прямокутник
SS_WHITEFRAME - білий контур прямокутника
для опису прямокутника заданого кольору.
Ми можемо описати статичний елемент - піктограму (іконку), вказавши стиль SS_ICON. Як заголовок вікна зачеплена ім'я ресурсу типу ICON, включеного у Ваше додаток. Розміри визначаються розмірами іконки незалежно від вказаних Вами.
Якщо нам треба замінити одну ікону на іншу, то треба цьому дочірньому вікна послати повідомлення (STM_SETICON, hIcon, 0L), а якщо ми хочемо тільки дізнатися хендл іконки, то треба послати повідомлення (STM_GETICON, 0, 0L). Обидва повідомлення повертають хендл іконки.
Частіше використовується інший різновид статичні елементи - текст. Заголовок вікна визначає виведений текст, який може бути виведений в один рядок, автоматично розміщений в декількох рядках і вирівняний на ліву чи праву кордон або центрований, що задається стилем вікна:
SS_SIMPLE, SS_LEFT, SS_LEFTNOWORDWRAP, SS_RIGHT, SS_CENTER
При цьому треба звернути увагу на стиль SS_NOPREFIX; Зазвичай послідовність з & і будь-якого символу позначає підкреслений символ. Однак це не завжди зручно - наприклад, якщо виведений текст є ім'ям файлу або директорії (у цьому випадку & може міститися в рядку як звичайний символ). Для того, що б заборонити використання & в якості префікса, використовується стиль SS_NOPREFIX.

Кнопки

Самий "багатий" клас - клас кнопок. Для створення вікна, належить цьому класу треба вказати ім'я класу "BUTTON". Більшість кнопок (але не всі) є активними елементами (тобто можуть приймати фокус вводу). Зазвичай кнопки посилають батьківському вікну тільки один код сповіщення - BN_CLICKED, який вказує на те, що кнопка була натиснута. Всі інші коди сповіщення кнопок (BN_?) Відповідають окремого випадку кнопок, який не рекомендується використовувати в Windows 3.1.
До цього класу належать такі різновиди елементів керування:
BS_PUSHBUTTON і BS_DEFPUSHBUTTON позначають кнопку, на яку можна "натиснути". Натискають на кнопку або пробілом, або мишкою. Стиль BS_DEFPUSHBUTTON позначає кнопку, яка повинна натискатися клавішею Enter, навіть якщо фокус введення належить іншому керуючому елементу.
BS_CHECKBOX і BS_AUTOCHECKBOX позначають прапорець - елемент, який складається з невеликого квадрата і рядки тексту. У квадраті може бути поставлений хрестик (check mark) - тобто цей елемент є "двохпозиційним перемикачем" - відзначений / неотмечен.
BS_AUTOCHECKBOX відрізняється від звичайного прапорця тим, що автоматично перемикається з одного стану в інше при натисканні на нього, а для простого BS_CHECKBOX ви повинні самі подати команду для перемикання.
BS_3STATE і BS_AUTO3STATE дуже схожий на прапорець, але може бути в трьох станах - відзначений / неотмечен / заборонений (у забороненому стані не приймає повідомлення від клавіатури і миші і малюється сірим. Цей стан включається і вимикається тільки програмним способом).
BS_RADIOBUTTON і BS_AUTORADIOBUTTON позначає перемикач (радіо-кнопку) - елемент, схожий на прапорець, але замість квадрата малюється гурток, в якому може бути поставлена ​​жирна крапка. Призначений для використання в групі інших радіо кнопок - причому тільки одна з них може бути натиснута, а інші повинні бути відпущені (як селектори діапазону в радіоприймачі).
BS_GROUPBOX редставляет собою прямокутну рамку, у верхній частині якої може бути виведений текст. Використовується для візуального об'єднання кількох керуючих елементів в одну групу. Хоча GroupBox і є кнопкою, але він не може отримувати фокус вводу - тобто більше схожий на статичні елементи.
Кнопки можуть обробляти 5 специфічних повідомлень:
BM_SETCHECK nCheck 0L
встановлює стан кнопки:
0 - неотмечена
1 - відзначена
2 - заборонена (тільки BS_3STATE і BS_AUTO3STATE)
BM_SETSTATE nState 0L
встановлює стан кнопки
0 - нормальний стан
1 - виділена (зобразити кнопку в "натиснутому" стані)
BM_SETSTYLE wStyle bRedraw & 0
змінити стиль кнопки. wStyle є комбінацією BS_??? стилів, а bRedraw вказує, чи треба перемальовувати кнопку.
BM_GETCHECK 0 0L
BM_GETSTATE 0 0L
повертають поточний стан кнопки.

Списки

Прості списки відносяться до класу LISTBOX. Елементи цього класу представляють собою один або декілька стовпців, в яких розміщується список рядків. Ви можете вибрати одну або кілька записів зі списку для подальшого використання. Список може мати або не мати смугу прокрутки, рядки в ньому можуть бути відсортовані або розміщені в порядку надходження.
Список розпізнає велику кількість специфічних повідомлень, тому тут будуть розглянуті лише деякі з них.
LB_RESETCONTENT 0 0L
це повідомлення призводить до видалення всіх даних зі списку.
LB_ADDSTRING 0 lpszString
додати рядок у кінець списку
LB_FINDSTRING nIndexStart lpszString
знайти потрібний рядок в списку і отримати її індекс
LB_DELETESTRING nIndex 0L
видалити рядок зі списку
LB_GETTEXT nIndex lpsBuffer
прочитати рядок з індексом nIndex в списку і розмістити її в указаном буфері.
LB_GETCURSEL 0 0
отримати індекс поточного вибраного елемента
LB_DIR nAttr lpszMask
заповнити список іменами файлів, директорій та дисків. Іноді зручно користуватися спеціальною функцією, посилаеющей це повідомлення: DlgDirList і DlgDirSelect.
Посилані батьківському вікну коди повідомлення можуть інформувати його про наступні події списку:
LBN_ERRSPACE - про що сталася помилку, пов'язану з браком пам'яті;
LBN_KILLFOCUS і LBN_SETFOCUS - про одержання або втрати фокусу вводу;
LBN_DBLCLK - про подвійне натискання на кнопку миші;
LBN_SELCHANGE - про зміну поточного вибраного елемента;
LBN_SELCANCEL - процес вибору перерваний, наприклад, переходом до іншого вікна.
Існує ще один різновид списків - так звані комбіновані списки, що складаються з невеликої віконця редактора і простого списку, розміщеного під ним. Ці списки належать до класу COMBOBOX. Виділяють три різновиди комбінованих списків, визначених його стилем:
· Простий комбінований список - CBS_SIMPLE - коли і редактор і список постійно видні;
· Випадає комбінований список - CBS_DROPDOWN - коли постійно мабуть віконце редактора і спеціальна кнопка праворуч, при натисканні на яку під редактором з'являється (випадає) список.
· Незмінний комбінований список - CBS_DROPDOWNLIST - аналогічний CBS_DROPDOWN, але текст у редакторі не може бути змінений.
Комбіновані списки дозволяють легко отримувати поповнюваний під час роботи список, але автоматичне поповнення не передбачено. Для цього Вам треба буде самим, переконавшись, що текст у редакторі не є у списку, додати його до списку.
Такий список може мати стиль CBS_OEMCONVERT, який призводить до автоматичного перетворення записуваних в нього рядків з OEM в ANSI, і до зворотного перетворення при читанні з нього даних.
Комбіновані списки підтримують ще більше повідомлень і кодів повідомлення, пов'язаних із застосуванням редактора і можливістю появи і приховування списку.

Редактор

Один з найбільш зручних стандартних класів - клас редактора EDIT. Вікна, що належать до цього класу можуть являти собою як однорядкові, так і багаторядкові редактори, можливо мають смуги прокручування і навіть віконця перегляду - введення і редагування в яких заборонені. До таких редакторам легко додавати додаткові операції, наприклад, пошук або заміну тексту. Найістотнішим недоліком є ​​те, що весь редагований текст розміщується в локальному блоці пам'яті, і, відповідно, обмежений розміром цієї пам'яті - не більше 64K мінус вже зайняте простір.
Весь редагований текст являє собою одну довгу, що закінчується \ 0 рядок, можливо містить символи табуляції, перекладу рядка і повернення каретки.
Найпростіший спосіб створити власний редактор - при створенні власного вікна на всю його внутрішню область встановити вікно стандартного редактора і додати кілька додаткових функцій - меню, читання / запис файлу, пошук / заміну та ін Строго кажучи, текстовий редактор NotePad зроблений саме таким методом.
Віконце редактора може бути використано для редагування невеликого тексту, тоді для його читання або завдання зручно використовувати функції
void SetWindowText (hWnd, lpszText);
int GetWindowText (hWnd, lpsBuffer, nMaxCount);
int GetWindowTextLength (hWnd);
або повідомленнями WM_SETTEXT, WM_GETTEXT і WM_GETTEXTLENGTH, які в разі платформи Win32 дозволять отримати або змінити текст у вікні, що належить іншому процесу, в той час як розглянуті функції можуть працювати тільки з вікнами, що належать даному процесу.
Однак з великими текстами зручніше працювати як з окремими блоками пам'яті. Для цього треба буде скористатися повідомленнями:
EM_GETHANDLE 0 0L
для отримання хендла блоку, що містить текст;
EM_SETHANDLE hLocal 0L
для завдання хендла блоку, що містить текст;
EM_LIMITTEXT nMaxChars 0L
для завдання максимального розміру тексту;
Як всі стандартні класи дочірніх вікна, вікна EDIT посилають батьківському вікну повідомлення про події, що відбуваються - помилково з-за браку пам'яті, отриманні та втрати фокусу, зміні редагованого тексту і про "прокручуванні" тексту у віконці редактора.

Смуги прокручування

Останній розглядається нами стандартний клас дочірніх вікон - смуги прокручування, що належать до класу SCROLLBAR. Взаємодія смуг прокрутки з батьківським вікном відрізняється від взаємодії всіх інших стандартних класів.
Ви можете самі створювати смуги прокручування, але, якщо вам треба одну-дві смуги прокручування знизу і праворуч від вікна, то простіше створити вікно зі стилями WS_VSCROLL та / або WS_HSCROLL. При цьому вікно автоматично отримає потрібні смуги прокручування. Зручність полягає ще й у тому, що ці смуги прокручування розміщуються поза внутрішньої області вікна, тобто Вам не треба враховувати їх розмір.
Для сповіщення батьківського вікна смуги прокручування посилають повідомлення WM_VSCROLL і WM_HSCROLL в залежності від типу смуги - горизонтальна або вертикальна, а для управління смугами прокрутки використовуються спеціальні функції.
Спочатку розглянемо повідомлення смуги прокручування:
WM_VSCROLL ScrollCode wndScroll & nPos
WM_HSCROLL ScrollCode wndScroll & nPos
в параметрі wPar розміщується код, який вказує що відбувається зі смугою прокрутки, старше слово lPar містить хендл смуги прокрутки, а молодше слово може вказувати на становище "движка" смуги.
Коди смуги прокрутки можуть бути наступні:


Для всіх кодів, крім SB_THUMBTRACK і SB_THUMBPOSITION, молодше слово lPar не використовується. Коди SB_THUMBTRACK надсилаються коли Ви, "зачепивши" мишкою движок смуги прокрутки, починаєте переміщати його. При цьому вони посилаються так часто, як встигають оброблятися - інформуючи Вас про поточне положення движка. Код SB_THUMBPOSITION посилається тільки в той момент, коли Ви відпускаєте кнопку миші для позиціонування движка в новому місці.
Крім цих кодів зарезервовано ще два - SB_TOP і SB_BOTTOM, які ніколи не надсилаються смугою прокручування. Власне смуги прокручування підтримують інтерфейс тільки з мишею, фокусу введення вони не отримують, тому при використанні смуг прокручування виникає необхідність додавання інтерфейсу з клавіатурою.
Часто роблять так, що батьківське вікно, обробляючи повідомлення від клавіатури просто посилає саме собі повідомлення "від імені" смуги прокручування. Вся обробка прокручування вікна зосереджена на повідомленнях WM_VSCROLL і WM_HSCROLL. У цьому випадку клавішах Home і End повинні відповідати якісь коди смуги прокручування, для чого і додані коди SB_TOP і SB_BOTTOM.
Звичайно, Ви можете йти іншим шляхом, тоді ці два коду Вам не знадобляться.
Наведемо невеликий приклад обробки повідомлення WM_KEYDOWN батьківським вікном:
UINT n;
switch (wMsg) {
...
case WM_KEYDOWN:
switch (wPar) {
case VK_HOME: n = SB_TOP; goto post_vscroll;
case VK_END: ​​n = SB_BOTTOM; goto post_vscroll;
case VK_PRIOR: n = SB_PAGEUP; goto post_vscroll;
case VK_NEXT: n = SB_PAGEDOWN; goto post_vscroll;
case VK_DOWN: n = SB_LINEDOWN; goto post_vscroll;
case VK_UP: n = SB_LINEUP;
post_vscroll:
PostMessage (hWnd, WM_VSCROLL, n, 0L);
break;
default: break;
}
return 0;
...
}
Далі нас будуть цікавити засоби для керування смугами прокручування. Кожна смуга прокрутки характеризується діапазоном прокрутки, тобто мінімальним і максимальним значеннями позиції движка. При створенні смуги прокручування її діапазон встановлюється в 0 .. 100;
Для того, що б можна було дізнатися або змінити діапазон смуги прокручування призначені функції:
void GetScrollRange (hWnd, nBar, lpnMin, lpnMax);
int SetScrollRange (hWnd, nBar, nMin, nMax, bRepaint);
Зручно встановлювати діапазон прокручування рівним, наприклад, числу рядків в редагованому файлі.
Деяких пояснень вимагають параметри hWnd і nBar. Параметр hWnd може задавати хендл вікна-батька, тоді за допомогою параметра nBar Ви вказуєте, яка конкретно смуга прокрутки мається на увазі: SB_VERT або SB_HORZ. А якщо hWnd є Хенлі смуги прокручування, то Ви повинні вказати nBar рівним SB_CTL.
За допомогою двох наступних функцій Ви можете дізнатися поточне положення движка смуги або встановити його в необхідну позицію.
Int GetScrollPos (hWnd, nBar);
int SetScrollPos (hWnd, nBar, nPos, bRepaint);
Остання функція дозволяє показати або заховати смуги прокручування. Вона може використовувати ще одне значення параметра nBar - SB_BOTH, вказуючи, що обидві смуги показуються або ховаються.
Void ShowScrollBar (hWnd, nBar, bShow);

Вікна, що малюються користувачем

Для деяких стандартних класів дочірніх вікон можливе створення вікон нестандартного вигляду. Це так звані малюються користувачем (Owner Draw) вікна. Ви можете створювати такі кнопки, і елементи списків (тобто Ви можете наповнювати список довільними об'єктами, наприклад, малюнками). Той же спосіб може бути застосований для малювання пунктів меню.
Для того, що б скористатися цією можливістю, Ви повинні вказати відповідний стиль - BS_OWNERDRAW для кнопки, LBS_OWNERDRAWFIXED, LBS_OWNERDRAWVARIABLE, CBS_OWNERDRAWFIXED, CBS_OWNERDRAWVARIABLE для списків. У випадку списків розрізняються два види змальованих користувачем елементів - елементи однакової висоти (... FIXED) і елементи довільної висоти (... VARIABLE).
Дочірні вікна таких стилів будуть посилати своєму батьківському вікну повідомлення WM_MEASUREITEM і WM_DRAWITEM. Обробляючи ці повідомлення батьківське вікно визначає розміри необхідних елементів і здійснює їх малювання. (Ці ж повідомлення можуть застосовуватися для малювання меню).
WM_MEASUREITEM nID lpMI
це повідомлення надсилається для визначення розмірів малюється елемента. Параметр wPar містить ідентифікатор дочірнього вікна, а параметр lPar - далекий покажчик на структуру MEASUREITEMSTRUCT, яку треба заповнити.
typedef struct tagMEASUREITEMSTRUCT {/ * mi * /
UINT CtlType; / / тип малюється елемента
UINT CtlID; / / ідентифікатор
UINT itemID; / / ідентифікатор елемента (номер пункту)
UINT itemWidth; / / ширина елемента
UINT itemHeight; / / висота елементу
DWORD itemData; / / дані елемента
} MEASUREITEMSTRUCT;
Поля CtlType, CtlID, itemID і itemData заповнюються Windows, ви будете їх використовуватися для визначення потрібного елемента.
Поле CtlType може бути одним з наступних:
ODT_BUTTON - кнопка
ODT_COMBOBOX - елемент комбінованого список
ODT_LISTBOX - елемент простого список
ODT_MENU - елемент меню
Поля CtlID і ItemID визначають ідентифікатори дочірнього вікна і елемента цього дочірнього вікна (якщо дочірнє вікно є списком або малюється елемент меню).
Поле ItemData є значенням, яке Ви передали або при створенні дочірнього вікна (ім'я кнопки) або при додаванні елемента в список або меню (див. повідомлення CB_ADDSTRING, CB_INSERTSTRING, LB_ADDSTRING, LB_INSERTSTRING і функції InsertMenu, AddMenu). Зазвичай це поле є покажчиком на назву вікна / елементу.
Два поля itemHeight і itemWidth ви повинні визначити самі. При цьому треба мати на увазі, що некоректне завдання цих полів або некоректна обробка повідомлення WM_DRAWITEM може призвести до непередбачуваних результатів, так як Windows не перевіряє коректності значень і виконаних дій).
WM_DRAWITEM nID lpDI
а це повідомлення надсилається, коли необхідно намалювати потрібний елемент. Параметр lPar є далеким покажчиком на структуру DRAWITEMSTRUCT, яка містить необхідні для малювання дані.
typedef struct tagDRAWITEMSTRUCT {/ * ditm * /
UINT CtlType; / / тип малюється елемента
UINT CtlID; / / ідентифікатор
UINT itemID; / / ідентифікатор елемента (номер пункту)
UINT itemAction; / / з-за чого треба малювати
UINT itemState; / / як треба малювати
HWND hwndItem; / / хендл вікна малюється елемента
HDC hDC; / / хендл контексту пристрої для малювання
RECT rcItem; / / прямокутник, в якому треба малювати
DWORD itemData; / / дані елемента
} DRAWITEMSTRUCT;
Звернемо увагу на поля itemAction і itemState. Вони в деякій мірі дублюють один одного, так як itemState вказує поточний стан елемента, а itemAction - причину малювання, наприклад отримання фокусу або вибір елемента. Для спрощення логіки малювання, можна перемальовувати всі віконце, орієнтуючись тільки на полі itemState, вказує як треба малювати.
Якщо треба намалювати елемент, який має фокус, то можна оспользоваться функцією
void DrawFocusRect (hDC, lpRect);
яка малює пунктирний прямокутник, зазвичай зображає елемент, що має фокус вводу.

Управління кольором дочірніх вікон

Вікна, що належать до стандартних класів дочірніх вікон, передбачають спеціальний механізм для управління їх кольором. Він заснований на використанні повідомлення WM_CTLCOLOR, яке дочірнє вікно посилає батьківському для визначення потрібних квітів.
WM_CTLCOLOR DC CtlType & hwndChild
Параметри цього повідомлення такі:
wPar містить хендл контексту пристрою малюється вікна молодше слово lPar містить хендл цього вікна, а старше - тип малюється вікна:
CTLCOLOR_BTN, CTLCOLOR_DLG, CTLCOLOR_EDIT, CTLCOLOR_LISTBOX, CTLCOLOR_MSGBOX, CTLCOLOR_SCROLLBAR, CTLCOLOR_STATIC
Обробляючи це повідомлення, Ви повинні встановити необхідні атрибути, наприклад, кольору тексту, фону, режим заповнення фону в зазначеному контексті пристрою і повернути хендл кисті, яка буде використовуватися для зафарбовування фону.
На жаль, не всі стандартні керуючі елементи коректно використовують це повідомлення. Наприклад, що натискаються кнопки використовують зазначену Вами кисть для малювання фону під кнопкою, а сама кнопка використовує сіру кисть - так що Ваш вибір не використовується.
Додати в блог або на сайт

Цей текст може містити помилки.

Програмування, комп'ютери, інформатика і кібернетика | Лекція
61.9кб. | скачати


Схожі роботи:
Робота з вікнами
Робота з вікнами 2
Робота з вікнами
Робота з діалоговими вікнами
Профілювальники додатків
Створення додатків на AJAX
Забезпечення продуктивності додатків
Засоби створення мультимедійних додатків
Різні способи друку з додатків
© Усі права захищені
написати до нас
Рейтинг@Mail.ru