Меню і акселератори в Visual C + +, Різне, Програмування, статті

У цій статті я вас ознайомлю з класом CMenu. За допомогою цього класу можна створювати меню в MFC додатках. Так само буде розглянуто питання про використання акселераторів. Отже, почнемо з опису класу CMenu. Клас CMenu
Розглянемо деякі найбільш важливі функції і змінні цього класу.

° m_hMenu? дескриптор меню, пов’язаний з об’єктом класу CMenu.
° BOOL CreateMenu ()? створює пусте меню і пов’язує його з об’єктом класу CMenu.
° BOOL CreatePopupMenu ()? створює пусте меню, що випадає і з’єднує з об’єктом класу CMenu.
° BOOL LoadMenu (UINT nIDResource)? завантажує меню з ресурсів і з’єднує його з об’єктом класу CMenu. Меню може бути створено програмним шляхом методу заповнення структур MENUITEMTEMPLATEHEADER і MENUITEMTEMPLATE і за допомогою виклику методу LoadMenuIndirect (const MUNUTEMPLATE * lpMenuTemplate).
° BOOL Attach (HMENU hMenu)? припасування існуючого меню до об’єкта класу CMenu. Якщо відомий дескриптор меню, то можна визначити вказівник на відповідний йому об’єкт CMenu за допомогою наступного методу static CMenu * PASCAL FromHandle (HMENU hMenu).
° BOOL DestroyMenu ()? руйнує об’єкт CMenu і звільняє всі ресурси. Цей метод зазвичай не викликається явно, так як він автоматично викликається з деструктора.
° BOOL DeleteMenu (UINT uPosition, UINT uFlags)? метод видаляє вказаний елемент меню. uPosition? визначає видаляється елемент меню. uFlags? визначає, як інтерпретується перший параметр. Якщо прапор дорівнює MF_BYCOMMAND, то перший параметр інтерпретується як ідентифікатор пункту меню. Якщо параметр дорівнює MF_BYPOSITION, то перший параметр визначає позицію елемента меню. Перший елемент має позицію нуль.
° BOOL TrackPopupMenu (UINT nFlags, int x, int y, CWnd * pWnd, LPCRECT lpRact = 0)? метод здійснює відображення спливаючого (контекстного) меню. Спливаюче меню може бути відображено в будь-якому місці екрану. Метод автоматично відстежує вибір пункту меню. nFlags? може бути заданий наступними константами: TPM_CENTERALIGN, TMP_LEFTALIGN, TMP_RIGHTALIGN? для вказівки позиції вирівнювання по горизонталі щодо координати x, TMP_LEFTBUTTON, TMP_RIGHTBUTTON? для визначення кнопки миші, що виконує вибір пункту меню. Координати x, y? позиція меню. pWnd? покажчик на вікно, в якому знаходиться це меню. Параметр lpRect? визначає прямокутну область, в якій клацання миші не викликає зникнення меню. Якщо значення параметра NULL, то область обмежена вікном меню.
° BOOL AppenedMenu (UINT nFlags, UINT_PTR nIDNewItem = 0, LPCTSTR lpszNewItem = NULL) і BOOL AppenedMenu (UINT nFlags, UINT_PTR nIDNewItem, const CBitmap * pBmp) Використовуються для додавання елемента в кінець меню. Параметр nFlags може бути комбінацією наступних констант: MF_CHECKED? перемикається елемент, стан? включений? (Відзначається галочкою). MF_UNCHECKED? перемикається елемент, стан? вимкнений? (Галочки немає). MF_DISABLED? елемент не лоступен. MF_ENABLED? елемент доступний. MF_GRAYED? 2серий? елемент (блокований). MF_MENUBARBREAK? елемент лінійки меню. MF_OWNERDRAW? самоотображаемий елемент., мене саме відповідає за відображення елемента. MF_POPUP? елемент меню має підменю. MF_SEPARATOR? відображення горизонтальної розділової лінії. MF_STRING? елемент є текстовим рядком. Параметр nIDNewItem? в залежності від першого параметра отпеделяет або ідентіфікаторор нового елемента, або покажчик (HMENU) підменю; ігнорується для значення MF_SEPARATOR. Параметр lpszNewItem визначає вміст нового елемента. Параметр pBmp? визначає покажчик на об’єкт класу CBitmap, який може використовуватися в якості вмісту рядка меню. При цьому перший параметр не може приймати значення MF_OWNERDRAW і MF_STRING.
° BOOL InsertMenu (UINT nPosition, UINT nFlags, UINT_PTR nIDNewItem = 0, LPCTSTR lpszNewItem = NULL) і BOOL InsertMenu (UINT nPosition, UINT nFlags, UINT_PTR nIDNewItem = 0, const CBitmap * pBmp)? постачають новий елемент у позицію, определяемцю параметром nPosition.
° UINT CheckMenuItem (UINT nIDCheckItem, UINT nCheck)? встановлює або скидає галочку у елемента меню. Другий параметр може приймати два значення: MF_CHECKED і MF_UNCHECKED в комбінації з параметрами MF_BYCOMMAND і MF_BYPOSITION.
° UINT EnableMenuItem (UINT nIDEnableItem, UINT nEnable)? метод встановлює для зазначеного елемента одне з наступних значень: MF_DISABLES і MF_ENABLED, MF_GRAYED.
° UINT GetMenuItemCount ()? повертає кількість елементів меню.
° UINT GetMenuItemID (int nPos)? метод повертає ідентифікатор зазначеного елемента меню.
° Int GetMenuString (UINT nIDItem, lptstr lpString, int nMaxCount, UINT nFlags) і int GetMenuString (UINT nIDItem, CString & rString, UINT nFlags)? визначають напис на зазначеному елементі меню.
° BOOL RemoveMenu (UINT nPosition, UINT nFlags)? метод видаляє вказаний елемент меню.
° UINT GetMenustate (UINT nID, UINT nFlags)? визначає стан елемента або число елементів у спадному меню. Другий параметр визначає те, як інтерпретувати перший елемент? ідентифікатор або позиція елемента меню. Для розкривається меню старший байт значення, що повертається містить число елементів в ньому, молодший байт? набір прапорів. Для меню верхнього рівня все повертаються значення є набором прапорів.
° Хоча сам редактор меню, пропонований Visual Studio.NET, дуже зручний, наведу структуру мене, тобто те, як воно зберігається в текстовому файлі ресурсів.






IDR_MENU1 MENU
BEGIN
POPUP “File”
BEGIN
MENUITEM “Open”, ID_FILE_OPEN131
MENUITEM “Exit”, ID_FILE_EXIT
END
POPUP “File2”
BEGIN
MENUITEM “Open2”, ID_FILE2_OPEN2
MENUITEM “Exit2”, ID_FILE2_EXIT2
END
POPUP “Help”
BEGIN
MENUITEM “About”, ID_HELP_ABOUT
END
END
 

Як бачите, мене має ідентифікатор IDR_MENU1, який, зрозуміло, має числове вираження. Якщо ми подивимося таблицю Resource Symbols, то побачимо, що числове вираження цього ідентифікатора 129 (у автора). Як ви напевно вже знаєте, числові значення ідентифікаторів зберігаються в файлі resource.h. Такі ж ідентифікатори має кожен елемент меню. Це дуже важливо, тому що в програмі ми фактично маємо справу не з меню, а з його елементами.
Тепер розберемо алгоритм установки меню в діалогове вікно. Для цієї мети природно потрібно вибрати функція OnInitDialog. Визначимо на початку файлу покажчик cm: CMenu * cm;. Наступний крок? це створення об’єкту класу CMenu: cm = new CMenu;. Тепер завантажуємо шаблон меню з файлу ресурсів: cm-> LoadMenu (IDR_MENU!). таким чином, наш об’єкт наповнився реальним змістом. Нарешті останнє, ми повинні пристикувати вийшов об’єкт до діалогового вікна. Це робиться таким дією

This->SetMenu(cm);

? This?, Як ви розумієте, вказує на об’єкт? діалогове вікно, SetMenu? метод, який здійснює бажану нами прістиковку. І все, цього вже достатньо, щоб у створеному діалоговому вікні з’явилося і меню. Так, не забудьте, закриваючи вікно, видалити меню з пам’яті, щоб не залишати за собою сміття. Робиться це дуже просто: delete cm.
Звичайно, цього ще не достатньо для повноцінного функціонування програми, так як пункти меню повинні працювати, тобто при виборі пункту повинна виконуватися якась процедура. Функцію-обробник можна зробити для кожного пункту меню. Робиться це точно тек само, як для будь-яких інших елементів діалогового вікна. Для цього, знаходячись в редакторі меню, потрібно натиснути правою кнопкою миші на потрібному елементі меню і вибрати Add Event Handler. Далі, у вікні вибирається ім’я функції і команда, яку ви хочете обробляти. Зрозуміло, цією командою буде COMMAND. Крім того, у вікні слід вибрати клас, де буде проводитися обробка. Слід вибрати клас, об’єктом якого є наше вікно. Далі, опинившись у потрібному файлі і в потрібній функції, можете вводити потрібний нам фрагмент коду, який буде виконуватися, коли буде обраний відповідний пунк меню. В принципі цього вже достатньо, щоб писати програми з меню.
Тепер звернемося до окремого, але тісно пов’язаному з меню питання? клавішах акселератора. Справа в тому що цей ресурс використовується в основному для швидкого доступу до елементів меню. Для того щоб клавіша-акселератор була пов’язана з відповідним пунктом меню, потрібно щоб ідентифікатори пункту меню і акселератора збігалися. Тоді обробник пункту меню і клавіші буде одним і тим же. Але для роботи акселератора потрібно зробити ще дві речі.
По-перше, слід завантажити таблицю акселераторів в пам’ять. Зробити це можна там же, де ви завантажуєте меню. Але от для діалогового вікна (точніше в класі CDialog) відповідного методу немає. Доведеться скористатися функцие API: LoadAccelerators. Завантажуючи таблицю, ця функція повертає дискриптор завантаженого ресурсу. Слід запам’ятати цей дискриптор в якій-небудь глобальної змінної. Напріметр, можна ввести додаткове властивість в об’єкт theApp. Першим аргументом функції є дескриптор програми, який може бути з допомогою глобальної функції AfxgetInstanceHandle (). Другим аргументом є ідентифікатор таблиці акселераторв, перетворений з допомогою макросу MAKEINTRESOURCE.
Отже, таблиця акселераторів завантажена, що далі? Далі, і це останнє, слід піддати додатковій обробці повідомлення, що приходить на вікно. Для цього достатньо переписати метод PreTransleteMessage.






BOOL CDemoMenuDlg::PreTranslateMessage(MSG*pMsg)
{
::TranslateAccelerator(this->m_hWnd, theApp.h,pMsg);
return CDialog::PreTranslateMessage(pMsg);
}
Як ви вже розумієте, CDemoMenuDlg? це об’єкт, який відповідає нашому діалогового вікна. Ось тепер все, наша таблиця акселераторів буде успішно працювати в парі з меню.
Теорія буде не повною, якщо я не приведу приклад.
// DemoMenuDlg.cpp : implementation file
//

#include “stdafx.h”
#include “DemoMenu.h”
#include “DemoMenuDlg.h”

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

// CDemoMenuDlg dialog
CMenu* cm;

CDemoMenuDlg::CDemoMenuDlg(CWnd* pParent /*=NULL*/)
: CDialog(CDemoMenuDlg::IDD, pParent)
{
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CDemoMenuDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
DDX_Control(pDX, IDC_CHECK1, m_check1);
}

BEGIN_MESSAGE_MAP(CDemoMenuDlg, CDialog)
ON_WM_PAINT()
ON_WM_RBUTTONUP()
ON_WM_QUERYDRAGICON()
//}}AFX_MSG_MAP
ON_COMMAND(ID_FILE_OPEN130, OnFileOpen130)
ON_BN_CLICKED(IDC_CHECK1, OnBnClickedCheck1)
END_MESSAGE_MAP()

// CDemoMenuDlg message handlers

BOOL CDemoMenuDlg::OnInitDialog()
{
CDialog::OnInitDialog();

// Set the icon for this dialog. The framework does this automatically
// when the application′s main window is not a dialog
SetIcon(m_hIcon, TRUE); // Set big icon
SetIcon(m_hIcon, FALSE); // Set small icon

// TODO: Add extra initialization here
theApp.h=::LoadAccelerators(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDR_ACCEL));

cm = new CMenu;
cm->LoadMenu(IDR_MENU1);
this->SetMenu(cm);

return TRUE; // return TRUE unless you set the focus to a control
}

// If you add a minimize button to your dialog, you will need the code below
// to draw the icon. For MFC applications using the document/view model,
// this is automatically done for you by the framework.

void CDemoMenuDlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // device context for painting

SendMessage(WM_ICONERASEBKGND, reinterpret_cast(dc.GetSafeHdc()), 0);

// Center icon in client rectangle
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() – cxIcon + 1) / 2;
int y = (rect.Height() – cyIcon + 1) / 2;

// Draw the icon
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialog::OnPaint();
}
}

// The system calls this function to obtain the cursor to display while the user drags
// the minimized window.
HCURSOR CDemoMenuDlg::OnQueryDragIcon()
{
return static_cast(m_hIcon);
}

BOOL CDemoMenuDlg::PreTranslateMessage(MSG*pMsg)
{
::TranslateAccelerator(this->m_hWnd, theApp.h,pMsg);
return CDialog::PreTranslateMessage(pMsg);
}

void CDemoMenuDlg::OnFileOpen130()
{
// TODO: Add your command handler code here
MessageBox(“Open”);
}

void CDemoMenuDlg::OnRButtonUp(UINT nFlags, CPoint point)
{
// TODO: Add your command handler code here
CMenu menu;

POINT pt;
GetCursorPos(&pt);

menu.LoadMenu(MAKEINTRESOURCE(IDR_MENU2));
menu.GetSubMenu(0)->TrackPopupMenu(0, pt.x, pt.y, this, NULL);
}

void CDemoMenuDlg::OnBnClickedCheck1()
{
if(!m_check1.GetCheck())
{
cm->EnableMenuItem(ID_FILE2_OPEN2, MF_ENABLED);
}
else
{
cm->EnableMenuItem(ID_FILE2_OPEN2, MF_GRAYED);
}
}

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


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

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

Ваш отзыв

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

*

*