Обработка извещений от Toolbar
Орган управления Toolbar посылает в родительское окно сообщения WM_COMMAND и WM_NOTIFY. О том, как обрабатывать первое из них, вы знаете из предыдущих томов "Библиотеки системного программиста", посвященных программированию для Microsoft Windows. Остановимся на обработке нового для вас сообщения WM_NOTIFY .
Через параметр wParam этого сообщения передается идентификатор органа управления. Если извещение пришло от Toolbar , то это должен быть идентификатор Toolbar.
Параметр lParam содержит указатель на структуру типа NMHDR или на структуру большего размера, содержащую в своем начале структуру NMHDR :
typedef struct tagNMHDR { HWND hwndFrom; UINT idFrom; UINT code; } NMHDR;
В этой структуре поле hwndFrom содержит идентификатор окна, приславшего сообщение, поле idFrom - идентификатор органа управления, приславшего сообщение, а поле code - код извещения.
Органы управления могут присылать следующие коды извещения:
Код извещения | Описание |
NM_CLICK | Пользователь сделал щелчок левой клавишей мыши внутри органа управления |
NM_DBLCLICK | Пользователь сделал двойной щелчок левой клавишей мыши внутри органа управления |
NM_RCLICK | Пользователь сделал щелчок правой клавишей мыши внутри органа управления |
NM_RDBLCLICK | Пользователь сделал двойной щелчок правой клавишей мыши внутри органа управления |
NM_RETURN | Когда орган управления имел фокус ввода, пользователь нажал клавишу <Enter> |
NM_KILLFOCUS | Орган управления потерял фокус ввода |
NM_SETFOCUS | Орган управления получил фокус ввода |
Перечисленные выше коды извещений используются всеми стандартными органами управления. Что же касается органа управления Toolbar , до для него имеются некоторые добавления.
Во-первых, параметр lParam сообщения WM_NOTIFY содержит указатель на структуру TBNOTIFY (содержащую в самом начале только что описанную структуру NMHDR ):
typedef struct { NMHDR hdr; int iItem; TBBUTTON tbButton; int cchText; LPTSTR pszText; } TBNOTIFY, FAR * LPTBNOTIFY;
В этой структуре поле iItem содержит номер кнопки, от которой пришло извещение (напомним, что нумерация кнопок начинается с нуля).
Структура tbButton типа TBBUTTON содержит описание кнопки. Мы уже рассказывали вам об этой структуре.
В поле cchText находится длина текстовой строки, соответствующей кнопке. Адрес этой строки передается через параметр pszText.
Во-вторых, для органа управления Toolbar определены дополнительные коды извещений:
Код извещения Toolbar | Описание |
TBN_BEGINADJUST | Пользователь приступил к настройке Toolbar |
TBN_BEGINDRAG | Пользователь начал передвигать кнопку по поверхности Toolbar |
TBN_ENDADJUST | Пользователь закончил настройку Toolbar |
TBN_ENDDRAG | Пользователь закончил передвижение кнопки по поверхности Toolbar |
TBN_CUSTHELP | Пользователь нажал кнопку "Help" в диалоговой панели, которая была вызвана для настройки Toolbar . Позже мы расскажем об этой диалоговой панели |
TBN_GETBUTTONINFO | Это извещение окно Toolbar посылает в том случае, если ему нужна информация об одной из кнопок |
TBN_QUERYDELETE | С помощью этого извещения окно Toolbar запрашивает возможность удаления кнопки в процессе настройки |
TBN_QUERYINSERT | С помощью этого извещения окно Toolbar запрашивает возможность вставки новой кнопки слева от указанной в процессе настройки |
TBN_RESET | Пользователь нажал кнопку "Reset" в диалоговой панели, которая была вызвана для настройки Toolbar |
TBN_TOOLBARCHANGE | Пользователь изменил внешний вид Toolbar в результате выполнения настройки |
LRESULT WndProc_OnNotify(HWND hWnd, int idFrom, NMHDR* pnmhdr) { LPTOOLTIPTEXT lpToolTipText; LPTBNOTIFY lptbn; int nItem; static CHAR szBuf[128];
switch(pnmhdr->code) { case TTN_NEEDTEXT: lpToolTipText = (LPTOOLTIPTEXT)pnmhdr; LoadString(hInst, lpToolTipText->hdr.idFrom, szBuf, sizeof(szBuf)); lpToolTipText->lpszText = szBuf; break;
case TBN_GETBUTTONINFO: lptbn = (LPTBNOTIFY)pnmhdr; nItem = lptbn->iItem; lptbn->tbButton.iBitmap = tbButtons[nItem].iBitmap; lptbn->tbButton.idCommand = tbButtons[nItem].idCommand; lptbn->tbButton.fsState = tbButtons[nItem].fsState; lptbn->tbButton.fsStyle = tbButtons[nItem].fsStyle; lptbn->tbButton.dwData = tbButtons[nItem].dwData; lptbn->tbButton.iString = tbButtons[nItem].iString;
return((nItem < sizeof(tbButtons)/sizeof(tbButtons[0]))? TRUE : FALSE); break;
case TBN_QUERYDELETE: lptbn = (LPTBNOTIFY)pnmhdr; nItem = lptbn->iItem; return (nItem == 0)? FALSE : TRUE; break;
case TBN_QUERYINSERT: lptbn = (LPTBNOTIFY)pnmhdr; nItem = lptbn->iItem; return (nItem == 0)? FALSE : TRUE; break;
case TBN_TOOLBARCHANGE: SendMessage(hwndTb, TB_AUTOSIZE, 0L, 0L); return TRUE; break;
default: break; } return FALSE; }
Рассмотрим особенности обработки отдельных извещений.
TTN_NEEDTEXT
Если при создании Toolbar был указан стиль TBSTYLE_TOOLTIP , пользователь может получить краткую справку о назначении любой кнопки Toolbar, просто установив на нее курсор мыши и подождав примерно одну секунду. При этом рядом с кнопкой появляется небольшое временное окно с описанием назначения кнопки.
Для того чтобы использовать эту возможность, в файле ресурсов приложения вы должны подготовить таблицу строк, содержащих краткое описание назначения кнопок. Лучше подготовить эту таблицу для всех строк меню, а не только для тех, которые дублируются кнопками Toolbar .
Вот пример такой таблицы (мы привели сокращенный вариант из приложения Smart Application):
STRINGTABLE DISCARDABLE BEGIN ID_FILE_NEW "Creates a new document" ID_FILE_OPEN "Open an existing document" ID_FILE_CLOSE "Closes the active document" ID_FILE_SAVE "Save the active document" ID_FILE_PRINT "Prints the active document" END STRINGTABLE DISCARDABLE BEGIN ID_FILE_EXIT "Exit application" ID_FILE_SAVEAS "Saves the active document under" " a different name" ID_HELP_ABOUT "Displays information about application" END
Как вы увидите в дальнейшем, эта таблица пригодится нам для органа управления Statusbar.
Когда пользователь устанавливает курсор мыши на кнопку Toolbar и оставляет его в покое, окно, создавшее Toolbar, получает извещение TTN_NEEDTEXT.
Обработчик извещения TTN_NEEDTEXT должен извлечь идентификатор кнопки, загрузить из ресурсов приложения соответствующую текстовую строку и записать ее адрес в поле lpszText:
case TTN_NEEDTEXT: lpToolTipText = (LPTOOLTIPTEXT)pnmhdr; LoadString(hInst, lpToolTipText->hdr.idFrom, szBuf, sizeof(szBuf)); lpToolTipText->lpszText = szBuf; break;
Вот и все, что нужно для того чтобы предоставить пользователю возможность определять назначение кнопок Toolbar с помощью органа управления Tool Tip.
TBN_GETBUTTONINFO
Это извещение преследует двоякую цель. Во-первых, с его помощью родительское окно может узнать, что пользователь внес изменения в Toolbar . Во-вторых, при помощи этого извещения функция окна органа управления Toolbar может получить информацию о любой кнопке Toolbar (если, конечно, приложение предоставит такую информацию).
Следующий фрагмент кода возвращает функции окна Toolbar сведения о кнопке, номер которой передается вместе с извещением:
case TBN_GETBUTTONINFO: lptbn = (LPTBNOTIFY)pnmhdr; nItem = lptbn->iItem; lptbn->tbButton.iBitmap = [nItem].iBitmap; lptbn->tbButton.idCommand = tbButtons[nItem].idCommand; lptbn->tbButton.fsState = tbButtons[nItem].fsState; lptbn->tbButton.fsStyle = tbButtons[nItem].fsStyle; lptbn->tbButton.dwData = tbButtons[nItem].dwData; lptbn->tbButton.iString = tbButtons[nItem].iString; return((nItem < sizeof(tbButtons)/sizeof(tbButtons[0]))? TRUE : FALSE); break;
Номер кнопки берется из поля iItem описанной ранее структуры TBNOTIFY, а информация о кнопке - из структуры tbButtons типа TBBUTTON, которая была подготовлена еще до создания Toolbar .
Обратите внимание на то, что обработчик извещения TBN_GETBUTTONINFO возвращает TRUE, если номер кнопки не вышел за пределы возможных значений индекса массива структур tbButtons. В противном случае возвращается значение FALSE.
Когда пользователь сделает двойной щелчок левой клавишей мыши по окну Toolbar для того чтобы вызвать диалоговую панель настройки этого органа управления, функция окна Toolbar будет присылать извещения TBN_GETBUTTONINFO до тех пор, пока соответствующий обработчик не вернет значение FALSE. При этом номер кнопки будет все время возрастать на единицу.
В документации SDK сказано, что обработчик извещения TBN_GETBUTTONINFO должен возвращать TRUE, если он предоставил информацию о нужной кнопке и FALSE в противном случае. Вы, конечно, можете возвращать значение FALSE для любого номера кнопки, не предоставляя никакой информации, однако при этом диалоговая панель настройки Toolbar будет работать неправильно. В частности, с ее помощью вы сможете удалить любую кнопку, но вернуть ее обратно будет уже невозможно.
TBN_QUERYDELETE
В процессе настройки органа управления Toolbar пользователь может удалить ненужные ему кнопки. Однако для некоторых кнопок вы можете запретить такую операцию, обеспечив специальную обработку извещения TBN_QUERYDELETE.
Если обработчик извещения вернет значение TRUE, пользователь сможет удалить кнопку, номер которой передается вместе с извещением в поле iItem. Если же обработчик вернет значение FALSE, кнопка останется на своем месте.
Ниже мы привели обработчик извещения TBN_QUERYDELETE, который запрещает удаление кнопки с номером ноль, но разрешает удаление любых других кнопок:
case TBN_QUERYDELETE: lptbn = (LPTBNOTIFY)pnmhdr; nItem = lptbn->; return (nItem == 0)? FALSE : TRUE; break;
TBN_QUERYINSERT
Извещение TBN_QUERYINSERT обрабатывается аналогично предыдущему.
Если обработчик этого извещения вернет значение TRUE, пользователь сможет вставить новую кнопку слева от той, номер которой передается в поле iItem. В противном случае вставка новой кнопки в данной позиции будет невозможна.
TBN_TOOLBARCHANGE
Извещение TBN_TOOLBARCHANGE посылается родительскому окну, создавшему Toolbar , когда пользователь изменил внешний вид этого органа управления.
В ответ родительское окно обычно посылает органу Toolbar сообщение TB_AUTOSIZE, которое вызывает автоматическое изменение размеров Toolbar:
case TBN_TOOLBARCHANGE: SendMessage(hwndTb, TB_AUTOSIZE, 0L, 0L); return TRUE; break;
TBN_BEGINADJUST
Это извещение поступает в родительское окно, когда пользователь приступил к настройке Toolbar . В ответ на него обработчик может вернуть любое значение, так как оно все равно будет проигнорировано.
TBN_ENDADJUST
Когда пользователь закончил настройку Toolbar , родительское окно получает извещение TBN_ENDADJUST. Соответствующий обработчик может вернуть любое значение.
TBN_BEGINDRAG
Если пользователь начал передвигать кнопку по поверхности Toolbar , родительское окно получает извещение TBN_BEGINDRAG. Так же как и в предыдущих двух случаях, обработчик извещения может вернуть любое значение.
TBN_ENDDRAG
Когда пользователь закончит передвижение кнопки по поверхности Toolbar , родительское окно получит извещение TBN_ENDDRAG. В ответ оно может вернуть любое значение.
TBN_RESET
Если родительское окно получило извещение TBN_RESET, это означает, что пользователь нажал кнопку "Reset" в диалоговой панели, которая была вызвана для настройки Toolbar . Обработчик этого извещения (если он предусмотрен), должен восстановить исходный вид органа управления Toolbar и вернуть любое значение.
Посылая органу Toolbar сообщение TB_SAVERESTORE вы можете сохранить в регистрационной базе данных и восстановить состояние Toolbar.
TBN_CUSTHELP
Извещение TBN_CUSTHELP передается родительскому окну, когда пользователь нажал кнопку "Help" в диалоговой панели, которая была вызвана для настройки Toolbar .
Обработчик этого извещения должен отобразить на экране соответствующий раздел справочной системы и вернуть любое значение.