
- •Уп. 5. Панель инструментов и строка состояния
- •5.1. Панель инструментов
- •5.1.1. Создание панели инструментов
- •5.1.2. Управление состоянием кнопок панели
- •5.1.3. Вывод подсказок в панели инструментов
- •5.2. Строка состояния
- •5.2.1. Создание строки состояния
- •5.2.2. Сообщения о меню в строке состояния
- •Контрольные вопросы
- •Упражнения
5.1.3. Вывод подсказок в панели инструментов
При остановке курсора мыши над любой кнопкой панели инструментов можно отображать текст подсказки, связанный с этой кнопкой. Для этого используют механизм уведомительных сообщений, при котором у функции окна можно запросить текст и отобразить его.
Панель инструментов функции родительского окна посылает уведомительное сообщение WM_NOTIFY о том, что с ней что-то сделали или требуется дополнительная информация. Для идентификации отправителя и истолкования сообщения используют параметр lParam. Он указывает на структуру типа NMHDR, которая содержит код и дополнительную информацию сообщения. После обработки сообщения WM_NOTIFY можно возвращать любое значение.
Структура NMHDR описана следующим образом:
typedef struct { HWND hwndFrom;
UINT idFrom;
UINT code; } NMHDR;
Здесь hwndFrom – дескриптор пославшего сообщение органа управления, idFrom – идентификатор этого органа управления, code – специфический для органа управления код сообщения.
Структура NMHDR обычно является частью структуры более высокого уровня. В случае панели инструментов она является частью структуры TOOLTIPTEXT:
typedef struct { NMHDR hdr; LPTSTR IpszText; char szText[80];
HINSTANCE hinst; UINT uFlags;
} TOOLTIPTEXT;
Назначение полей этой структуры:
hdr – структура типа NMHDR.
IpszText – указатель на строку, которая содержит или получает текст для панели инструментов.
szText – буфер для получения текста от панели инструментов.
hinst – дескриптор приложения, которое содержит строковый ресурс. Если lpszText указывает на строку, hinst=NULL.
uFlags – флажок, который указывает, как интерпретировать значение поля idFrom структуры hdr. Если uFlags=TTF_IDISHWND, то idFrom – дескриптор, иначе idFrom – идентификатор кнопки панели инструментов.
Эти структуры обычно описывают и инициируют после получения сообщения WM_NOTIFY. Например, следующим образом:
Описывают указатель на структуру типа TOOLTIPTEXT:
LPTOOLTIPTEXT TTStr;
Связывают указатель TTStr с параметром lParam:
TTStr=(LPTOOLTIPTEXT)IParam;
Далее анализируют код сообщения и принимают соответствующее решение.
Например, в случае организации подсказок, анализ сводится к проверке:
if (TTStr->hdr.code!=TTN_NEEDTEXT) return 0;
То есть обработку завершают, если код не равен TTN_NEEDTEXT. Сообщение TTN_NEEDTEXT говорит, что для панели инструментов требуется текст.
Представим, что принято уведомительное сообщение от кнопки панели о том, что требуется некий текст. Тогда определяют идентификатор этой кнопки и записывают соответствующий текст. Эту процедуру можно реализовать многими способами. Например:
switch (TTStr->hdr.idFrom) { case CM_FILE_NEW:
{ TTStr-MpszText-'Создать новый документ";
return 0;
}
default: return 0;
}
В качестве подсказки можно посылать любые тексты (даже с управляющими символами типа \n).
Задача. В рассмотренном ранее приложении (листинг 4.6) к командам меню подключить кнопки панели инструментов и обеспечить выдачу подсказок в момент остановки курсора мыши над кнопкой панели.
Листинг 5.3. Выдача подсказок к кнопкам панели инструментов.
#include <windows.h>
#include <commctrl.h>
#pragma comment (lib, "comctl32.lib")
#define ID_TOOLBAR 100
#define CM_FILE_NEW 1000
#define CM_FILE_OPEN 1001
#define CM_FILE_SAVE 1002
#define CM_FILE_QUIT 1003
#define CM_EDIT_CUT 2000
#define CM_EDIT_PASTE 2001
#define CM_EDIT_COPY 2002
#define CM_EDIT_DEL 2003
#define CM_HELP_HELP 3000
#define CM_HELP_ABOUT 3001
BOOL RegClass(WNDPROC, LPCTSTR, UINT);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
HACCEL CreateAccelTable(void);
HINSTANCE hInstance;
TCHAR szClass[] = TEXT("NotifyClass");
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpszCmdLine, int nCmdShow)
{
MSG msg;
HWND hwnd;
hInstance = hInst;
if (!RegClass(WndProc, szClass, COLOR_WINDOW)) return FALSE;
hwnd = CreateWindow(szClass, TEXT("Выдача посказок"), WS_OVERLAPPEDWINDOW | WS_VISIBLE,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, hInstance, NULL);
if (!hwnd) return FALSE;
HACCEL hAccel = CreateAccelTable();
while(GetMessage(&msg, 0, 0, 0))
{
if (!hAccel || !TranslateAccelerator(hwnd, hAccel, &msg))
{ TranslateMessage(&msg); DispatchMessage(&msg); }
}
DestroyAcceleratorTable(hAccel);
return msg.wParam;
}
BOOL RegClass(WNDPROC Proc, LPCTSTR szName, UINT brBackground)
{
WNDCLASS wc;
wc.style = wc.cbClsExtra = wc.cbWndExtra = 0;
wc.lpfnWndProc = Proc;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(brBackground+1);
wc.lpszMenuName = NULL;
wc.lpszClassName = szName;
return (RegisterClass(&wc) != 0);
}
BOOL CreateMenuItem(HMENU hMenu, TCHAR *str, UINT uIns, UINT uCom, HMENU hSubMenu, BOOL flag, UINT fType)
{
MENUITEMINFO mii;
mii.cbSize = sizeof(MENUITEMINFO);
mii.fMask = MIIM_STATE | MIIM_TYPE | MIIM_SUBMENU | MIIM_ID;
mii.fType = fType;
mii.fState = MFS_ENABLED;
mii.dwTypeData = str;
mii.cch = sizeof(str);
mii.wID = uCom;
mii.hSubMenu = hSubMenu;
return InsertMenuItem(hMenu, uIns, flag, &mii);
}
HACCEL CreateAccelTable(void)
{
//Массив акселераторов
ACCEL Accel[8];
//Создать
Accel[0].fVirt = FVIRTKEY | FCONTROL;
Accel[0].key = 0x4e;
Accel[0].cmd = CM_FILE_NEW;
//Открыть
Accel[1].fVirt= FVIRTKEY | FCONTROL;
Accel[1].key = 0x4f;
Accel[1].cmd = CM_FILE_OPEN;
//Сохранить
Accel[2].fVirt= FVIRTKEY | FCONTROL;
Accel[2].key = 0x53;
Accel[2].cmd = CM_FILE_SAVE;
//Выход
Accel[3].fVirt= FVIRTKEY | FALT;
Accel[3].key = 0x73;
Accel[3].cmd = CM_FILE_QUIT;
//Вырезать
Accel[4].fVirt= FVIRTKEY | FCONTROL;
Accel[4].key = 0x58;
Accel[4].cmd = CM_EDIT_CUT;
//Вклеить
Accel[5].fVirt= FVIRTKEY | FCONTROL;
Accel[5].key = 0x56;
Accel[5].cmd = CM_EDIT_PASTE;
//Копировать
Accel[6].fVirt= FVIRTKEY | FCONTROL;
Accel[6].key = 0x43;
Accel[6].cmd = CM_EDIT_COPY;
//Удалить
Accel[7].fVirt= FVIRTKEY;
Accel[7].key = 0x2e;
Accel[7].cmd = CM_EDIT_DEL;
return CreateAcceleratorTable((LPACCEL)Accel, 8);
}
HWND CreateToolBar(HWND hwnd, DWORD dwStyle, UINT uCom)
{
static TBBUTTON but[10];
but[0].fsStyle=TBSTYLE_SEP;
//Создать
but[1].iBitmap = STD_FILENEW;
but[1].idCommand=CM_FILE_NEW;
but[1].fsState=TBSTATE_ENABLED;
but[1].fsStyle=TBSTYLE_BUTTON;
//Открыть
but[2].iBitmap=STD_FILEOPEN;
but[2].idCommand=CM_FILE_OPEN;
but[2].fsState=TBSTATE_ENABLED;
but[2].fsStyle=TBSTYLE_BUTTON;
//Сохранить
but[3].iBitmap=STD_FILESAVE;
but[3].idCommand=CM_FILE_SAVE;
but[3].fsState=TBSTATE_ENABLED;
but[3].fsStyle=TBSTYLE_BUTTON;
//Вырезать
but[4].iBitmap=STD_CUT;
but[4].idCommand=CM_EDIT_CUT;
but[4].fsState=TBSTATE_ENABLED;
but[4].fsStyle=TBSTYLE_BUTTON;
//Копировать
but[5].iBitmap=STD_COPY;
but[5].idCommand=CM_EDIT_COPY;
but[5].fsState=TBSTATE_ENABLED;
but[5].fsStyle=TBSTYLE_BUTTON;
//Вставить
but[6].iBitmap=STD_PASTE;
but[6].idCommand=CM_EDIT_PASTE;
but[6].fsState=TBSTATE_ENABLED;
but[6].fsStyle=TBSTYLE_BUTTON;
//Удалить
but[7].iBitmap=STD_DELETE;
but[7].idCommand=CM_EDIT_DEL;
but[7].fsState=TBSTATE_ENABLED;
but[7].fsStyle=TBSTYLE_BUTTON;
//Запрос помощи
but[8].iBitmap=STD_HELP;
but[8].idCommand=CM_HELP_HELP;
but[8].fsState=TBSTATE_ENABLED;
but[8].fsStyle=TBSTYLE_BUTTON;
return CreateToolbarEx(hwnd, dwStyle, uCom, 0, HINST_COMMCTRL,
IDB_STD_LARGE_COLOR, but, 9, 0, 0, 0, 0, sizeof(TBBUTTON));
}
LRESULT CALLBACK WndProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
static HMENU hMainMenu, hPopUpFile, hPopUpEdit, hPopUpHelp;
static HWND hToolbar;
switch (msg)
{
case WM_SIZE:
{ MoveWindow(hToolbar, 0, 0, 0, 0, TRUE); return 0; }
case WM_CREATE:
{
hMainMenu=CreateMenu();
hPopUpFile=CreatePopupMenu();
int i=0; //Инициализация позиции в меню
CreateMenuItem(hPopUpFile, TEXT("&Новый\t Ctrl+N"), i++, CM_FILE_NEW, NULL, FALSE, MFT_STRING);
CreateMenuItem(hPopUpFile, TEXT("&Oткрыть\t Ctrl+O"), i++, CM_FILE_OPEN, NULL, FALSE, MFT_STRING);
CreateMenuItem(hPopUpFile, TEXT("&Coxpaнить\t Ctrl+S"), i++, CM_FILE_SAVE, NULL, FALSE, MFT_STRING);
CreateMenuItem(hPopUpFile, NULL, i++, 0, NULL, FALSE, MFT_SEPARATOR);
CreateMenuItem(hPopUpFile, TEXT("В&ыход\t Alt+F4"), i++, CM_FILE_QUIT, NULL, FALSE, MFT_STRING);
hPopUpEdit=CreatePopupMenu();
i=0; //Инициализация позиции в меню
CreateMenuItem(hPopUpEdit, TEXT("&Bырезать\t Ctrl+X"), i++, CM_EDIT_CUT, NULL, FALSE, MFT_STRING);
CreateMenuItem(hPopUpEdit, TEXT("B&ставить\t Ctrl+V"), i++, CM_EDIT_PASTE, NULL, FALSE, MFT_STRING);
CreateMenuItem(hPopUpEdit, TEXT("&Копировать\t Ctrl+C"), i++, CM_EDIT_COPY, NULL, FALSE, MFT_STRING);
CreateMenuItem(hPopUpEdit, TEXT("&Удалить\t Delete"), i++, CM_EDIT_DEL, NULL, FALSE, MFT_STRING);
hPopUpHelp=CreatePopupMenu();
i=0; //Инициализация позиции в меню
CreateMenuItem(hPopUpHelp, TEXT("&Помощь\ F1"), i++, CM_HELP_HELP, NULL, FALSE, MFT_STRING);
CreateMenuItem(hPopUpHelp, NULL, i++, 0, NULL, FALSE, MFT_SEPARATOR);
CreateMenuItem(hPopUpHelp, TEXT("&О программе"), i++, CM_HELP_ABOUT, NULL, FALSE, MFT_STRING);
//Подключаем временные меню к главному меню
i=0; //Инициализация позиции в меню
CreateMenuItem(hMainMenu, TEXT("&Файл"), i++, 0, hPopUpFile, FALSE, MFT_STRING);
CreateMenuItem(hMainMenu, TEXT("&Правка"), i++, 0, hPopUpEdit, FALSE, MFT_STRING);
CreateMenuItem(hMainMenu, TEXT("&Помощь"), i++, 0, hPopUpHelp, FALSE, MFT_STRING);
SetMenu(hwnd, hMainMenu);
DrawMenuBar(hwnd);
DWORD dwStyle = WS_CHILD | WS_VISIBLE | TBSTYLE_TOOLTIPS | WS_DLGFRAME;
hToolbar=CreateToolBar(hwnd, dwStyle, ID_TOOLBAR);
return 0;
}
case WM_COMMAND:
{
switch (LOWORD(wParam))
{
case CM_FILE_NEW:
case CM_FILE_OPEN:
case CM_FILE_SAVE:
case CM_EDIT_CUT:
case CM_EDIT_PASTE:
case CM_EDIT_COPY:
case CM_EDIT_DEL:
case CM_HELP_HELP:
case CM_HELP_ABOUT: { return 0; }
case CM_FILE_QUIT: { DestroyWindow(hwnd); return 0; }
}
}
case WM_NOTIFY:
{
LPTOOLTIPTEXT TTStr;
TTStr=(LPTOOLTIPTEXT)lParam;
if (TTStr->hdr.code != TTN_NEEDTEXT) return 0;
switch (TTStr->hdr.idFrom)
{
case CM_FILE_NEW:
{ TTStr->lpszText = TEXT("Создать новый документ"); return 0; }
case CM_FILE_OPEN:
{ TTStr->lpszText = TEXT("Открыть существующий документ"); return 0; }
case CM_FILE_SAVE:
{ TTStr->lpszText = TEXT("Coxpaнить текущий документ"); return 0; }
case CM_EDIT_CUT:
{ TTStr->lpszText = TEXT("Вырезать и запомнить выделенный объект"); return 0; }
case CM_EDIT_PASTE:
{ TTStr->lpszText = TEXT("Bcтавить копированный объект"); return 0; }
case CM_EDIT_COPY:
{ TTStr->lpszText = TEXT("Копировать выделенный объект"); return 0; }
case CM_EDIT_DEL:
{ TTStr->lpszText = TEXT("Удаление выделенного объекта"); return 0; }
case CM_HELP_HELP:
{ TTStr->lpszText = TEXT("Добро пожаловать в справочную систему:\n\n",
"1. Найдите ответы на возникающие вопросы\n\n",
"2. Просмотрите электронную версию справочника"); return 0; }
case CM_HELP_ABOUT:
{ TTStr->lpszText = TEXT("Сообщение о программе"); return 0; }
case CM_FILE_QUIT:
{ TTStr->lpszText = TEXT("3aвершить работу приложения"); return 0; }
default: return 0;
}
return 0;
}
case WM_DESTROY: { PostQuitMessage(0); return 0; }
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
Рассмотрим, какие изменения потребовались для решения данной задачи.
Описан идентификатор панели инструментов:
#define ID_TOOLBAR 100
Описана функция создания панели инструментов:
HWND CreateToolBar(HWND hwnd, DWORD dwStyle, UINT uCom);
Она от предыдущих версий отличается другим составом кнопок и тем, что отсутствует управление состоянием кнопок.
Для того чтобы кнопки панели инструментов посылали сообщение WMNOTIFY, изменен стиль dwStyle окна панели инструментов:
DWORD dwStyle = WS_CHILD | WS_VISIBLE |
TBSTYLE_TOOLTIPS | WS_DLGFRAME;
Здесь применен стиль TBSTYLE_TOOLTIPS. Затем стиль dwStyle используют при вызове функции CreateToolBar для создания панели инструментов:
hToolbar = CreateToolBar(hwnd, dwStyle, ID_TOOLBAR);
Обработка уведомительного сообщения WM_NOTIFY.
Запоминают значение параметра lParam. Для этого описывают переменную-указатель на структуру типа TOOLTIPTEXT:
LPTOOLTIPTEXT TTStr;
Затем в эту переменную записывают значение параметра lParam:
TTStr = (LPTOOLTIPTEXT)lParam;
Если уведомительное сообщение WM_NOTIFY не требует текста подсказки, завершают обработку:
if (TTStr->hdr.code != TTN_NEEDTEXT) return 0;
Оператор варианта по идентификатору кнопки, которая послала сообщение WM_NOTIFY, записывает тот или иной текст в структуру TTStr:
switch (TTStr->hdr.idFrom)
{ case CM_FILE_NEW:
{ TTStr->lpszText = "Создать новый документ";
return 0;
}
case CM_FILE_QUIT:
{ TTStr->lpszText = "3aвершить работу приложения";
return 0;
}
default: return 0;
}
Как видно из листинга, здесь перечислены все команды меню. Хотя не для всех команд созданы кнопки на панели инструментов. В любом случае подсказка соответствует той кнопке, над которой остановился курсор мыши. Подсказки будут появляться в том случае, если кнопка отображена на панели. При этом операционную систему не интересует состояние кнопки: достаточно того, что кнопка посылает уведомительное сообщение WM_NOTIFY.
Другие изменения в тексте приложения не обязательны.
Данный способ обработки сообщения WM_NOTIFY отличается простотой, наглядностью и информативностью сообщений. Например, можно выдать большее сообщение:
TTStr->lpszText="Добро пожаловать в справочную систему:\n\n"
"1. Найдите ответы на возникающие вопросы.\n\n"
"2. Просмотрите электронную версию справочника";