Самі малюємо своє меню C + + Builder

Трохи раніше ми обговорили списки, промальовує їх власником Такі списки дозволяли вам відображати як елемент списку все, що захочете (текст, графіку, кольори, шрифти) Напевно, ви вже звернули увагу на те, що меню схоже на список Обидва ці обєкта дозволяють відображати якийсь список елементів У цьому вони дуже схожі Ще вони схожі в наступному: і той, і інший дозволяють відображати елементи списку в якому завгодно форматі З цієї точки зору, меню навіть краще списків Меню, як ми побачимо в цьому прикладі, дозволяє відображати тільки ті елементи, які ви дійсно хочете відобразити, і навіть дозволяє під час виконання вибирати – чи здійснює меню відображення того чи іншого елемента в якомусь своєму форматі, чи ні Отже, в цьому прикладі ми розглянемо деякі можливості відображення елементів меню в CBuilder, а також можливості зміни їх поведінки відповідно з цілями і завданнями вашої програми

Ви знайдете вихідний код прикладу програми роботи з власними меню в директорії

Chapter4 \ OwnerDrawMenu доданого компакт-диска

Якщо ви памятаєте, в розмові про відображуваних власником списках ми згадували про те, що для обробки такого відображення вам необхідно відстежити два повідомлення Windows Перше повідомлення – це WM_MEASUREITEM, яке надсилається кожному елементу в меню Це повідомлення має на увазі, що ви повідомили меню, наскільки високим кожен елемент повинен бути на екрані Повідомлення Windows WM_MEASUREITEM чадним чином укладено в подія OnMeasureItem форм CBuilder

Друге повідомлення, з яким ми зіткнемося при роботі з меню, відображеними їх власником, це WM_DRAWITEM Це повідомлення надсилається кожен раз, коли кожен з елементів повинен бути відмалювали На відміну від списку, повідомлення WM_DRAWITEM надсилатиметься кожен раз, коли меню буде відображатися, тому що стан елемента меню могло змінитися відтоді,

як він був відмалювали востаннє Ви можете робити все, що заманеться, отрісовивая елемент меню Відображайте растровий малюнок слідом за текстом, текст виводите новим шрифтом, або навіть намалюйте картинку замість тексту У теперішньому прикладі ми збираємося відображати просто кольорові прямокутники в якості елементів меню

Якщо ви переглянете методи компонентів VCL TMainMenu і TMenuItem, то не знайдете серед них жодного, який би був безпосередньо асоційований з меню, відображеними їх власником І все з однієї простої причини – Таких там немає Так що, якщо ви всерйоз захочете отримати такі у своєму додатку, вам доведеться мати справу безпосередньо з Windows API Не бійтеся – це не буде кошмаром, як було б, працюй ви в Visual Basic або навіть Delphi, які застосовують відмінні від API опису змінних Замість цього ви працюєте на C + +, мовою, який відмінно сумісний з мовою C, на якому і був, власне, написаний API Великий розмова про функції Windows API і CBuilder належить нам в наступному розділі

Функція Windows API, з якою нам доведеться зіткнутися в цьому прикладі, називається

ModifyMenu Функція ModifyMenu має наступний синтаксис:

ModifyMenuA( HMENU hMnu, UINT uPosition, UINT uFlags,

UINT uIDNewItem,

LPCSTR lpNewItem

)

де hMnu – посилання (handle) на меню uPosition – позиція елемента меню, який ви збираєтеся змінити всередині меню uFlags – безліч можливих прапорів, використовуваних при зміні цього елемента меню uIDNewItem – Ідентифікатор змінюваного елемента lpNewItem – або рядок, що відображається як елемент меню, або посилання на меню, в залежності від параметра uFlags

Параметр uFlags – це те саме місце, з яким повязана всю плутанина в роботі з цією функцією API Як правило ви будете визначати його як MF_BYCOMMAND або MF_BYPOSITION Значення MF_BYCOMMAND означає, що параметр uIDNewItem визначає ідентифікатор елемента меню (значення, яке ми визначаємо у властивості Command елемента меню) Значення ж MF_BYPOSITION показує, що параметр uIDNewItem визначає що відлічується від 0 індекс у список елементів меню для посилання на меню Використання цього аргументу означатиме, що перше значення буде 0 незалежно від значення властивості Command

Разом з прапором MF_BYCOMMAND або MF_BYPOSITION, ви можете встановити ще один прапор, що визначає, якого типу буде елемент меню Це може бути MF_STRING, MF_BITMAP або MF_OWNERDRAW У разі MF_STRING параметр lpNewItem буде вказувати на рядок, що використовується як текст елемента меню У разі MF_BITMAP параметр буде посиланням на растровий малюнок, а прапор MF_OWNERDRAW означає, що параметр не важливий Аргумент MF_BITMAP ми не будемо використовувати в даному прикладі

Чим витрачати прірву часу на пояснення того, яким чином різні прапори можуть бути використані і скомбіновані, куди простіше показати це на прикладі Отже, додайте елемент головного меню з імям «Fred» в меню Потім додайте другий елемент з імям «Irving» і третій, з назвою «Змінити» У пункт Fred додайте два підпункти з іменами «George» і

«Ralph» Це і будуть наші елементи меню, що відображаються їх власником Виключно для

того, щоб показати, що зміни в одному місці не впливають на елементи меню в іншому, додайте підпункт в пункт меню Irving з будь-яким, яким вам буде завгодно, імям У пункт меню Змінити додайте два підпункту з іменами «Зробити відображеними власником» та «Зробити нормальними» Ці два пункти будуть використовуватися для перемикання станів одного з наших елементів

Додайте новий обробник для події форми OnCreate Привласніть цьому оброблювачу імя

FormCreate У цей новий обробник додайте наступний код:

void __fastcall TForm1::FormCreate(TObject *Sender)

{

ModifyMenu(MainMenu1-&gtHandle, George1-&gtCommand,

MF_BYCOMMAND | MF_OWNERDRAW,

George1-&gtCommand, 0)

ModifyMenu(MainMenu1-&gtHandle, Ralph1-&gtCommand,

MF_BYCOMMAND | MF_OWNERDRAW,

Ralph1-&gtCommand, 0)

}

Як ви бачите, ми використовуємо функцію API ModifyMenu для того, щоб змінити два елементи меню (George і Ralph відповідно) так, щоб вони стали елементами, відображеними їх власником Команда ModifyMenu буде намагатися змінити команду, асоційовану з елементом меню, так що нам доведеться передавати її двічі, щоб уникнути змін Параметр нового елемента меню (останній) в даному випадку не використовується, так що ми просто передаємо команді 0

Якщо ви зараз запустите програму, то на двох елементах меню нічого не буде відображено Вийдіть з програми і додайте обробник для пункту меню George Це має служити підтвердженням того, що елементи меню продовжують працювати коректно незалежно від того, що ми з ними робимо У обробник додайте наступний код:

void __fastcall TForm1::George1Click(TObject *Sender)

{

MessageBox (NULL, Ви вибрали Джорджа”, Підтвердження, MB_OK)

}

Запустіть програму знову і клацніть на першому пункті меню Ви там нічого не побачите Виберіть другий підпункт, перемістивши миша до низу меню і відпустивши там кнопку Ви побачите вікно повідомлення, яке повідомить вам, який пункт меню ви обрали Тепер ми, принаймні, знаємо, що нічого не попсували – поки

Наступним кроком буде додавання обробників для визначення і власне відображення на екрані пунктів меню Сам по собі процес буде тим же самим, що і для списку, відображуваного його власником, і тому ми не будемо вдаватися в усі деталі того, що відбувається

Додайте обробник для події форми OnMeasureItem і назвіть його HandleMeasureItem, а в нього додайте наступний код:

void __fastcall TForm1::HandleMeasureItem(TMessage&amp Msg)

{

MEASUREITEMSTRUCT *lpmis = (LPMEASUREITEMSTRUCT)  MsgLparam

lpmis-&gtitemHeight = 12

lpmis-&gtitemWidth = 50

}

Цей метод всього лише модифікує структуру Measure Item Зверніть увагу на те, що оскільки спрямоване нам повідомлення є обєктом TMessage, ми повинні перетворити частину його (LParam) в покажчик на структуру, з якою будемо працювати Робота з меню, відображеними їх власники не настільки прозора, як з елементами списку, але все ж досить проста

Далі, додайте обробник для методу форми OnDrawItem Присвойте новому оброблювачу імя

HandleDrawItem і додайте в нього наступний код:

void __fastcall TForm1::HandleDrawItem(TMessage&amp Msg)

{

DRAWITEMSTRUCT *lpdis = (DRAWITEMSTRUCT *) MsgLParam

TCanvas *canvas = new TCanvas canvas-&gtHandle = lpdis-&gthDC

if ((int)lpdis-&gtitemID == George1-&gtCommand )

canvas-&gtBrush-&gtColor = clRed else

canvas-&gtBrush-&gtColor = clGreen

/ / Визначаємо прямокутник

TRect r

rLeft = lpdis-&gtrcItemleft rTop = lpdis-&gtrcItemtop rRight = lpdis-&gtrcItemright

rBottom = lpdis-&gtrcItembottom

canvas-&gtFillRect(r) delete canvas

}

Ще раз, оскільки втілення меню, відображуваного власником, не настільки просто, як аналогічного списку, зазначу, що ви повинні перетворити частину обєкта-структури TMessage в покажчик на обєкт DRAWITEMSTRUCT, який містить всі шматки коду для отрисовки меню Маючи структуру, ми використовуємо посилання (handle) на контекст пристрою (device context), що зберігається в цьому обєкті, для створення нового обєкта Canvas для використання в коді отрисовки Працювати з обєктом Canvas куди простіше, ніж з посиланням на контекст пристрою, що лежить в його основі, так що це робиться для нашої ж користі Все, що нам залишається зробити, це визначити, який колір вибрати, відштовхуючись від ідентифікатора itemID в структурі і заповнити цим кольором прямокутник, який передається нам в структурі Просто, як парена ріпа

Джерело: Теллес М – Borland C + + Builder Бібліотека програміста – 1998

Схожі статті:


Сподобалася стаття? Ви можете залишити відгук або підписатися на RSS , щоб автоматично отримувати інформацію про нові статтях.

Коментарів поки що немає.

Ваш отзыв

Поділ на параграфи відбувається автоматично, адреса електронної пошти ніколи не буде опублікований, допустимий HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*

*