платформа Win32 - Туториалы Iczelion'a на русском, адаптированные для FreeBasic. Урок 23 - Иконка в system tray

Предыдущая тема Следующая тема Перейти вниз

платформа Win32 - Туториалы Iczelion'a на русском, адаптированные для FreeBasic. Урок 23 - Иконка в system tray

Сообщение  electrik в Вт Июн 30, 2009 7:09 pm

Win32 API. Урок 23. Иконка в system tray

На этом Уроке мы узнаем, как помещать иконки в system tray и как создавать/использовать всплывающее меню.

Теория:

System tray - это прямоугольная область панели задач, в которой располагаются несколько иконок. Скорее всего, вы обнаружите там как минимум цифровые часы. Вы можете самостоятельно помещать иконки в system tray. Далее приводятся шаги, которые нужно для этого выполнить:

• Заполните структуру NOTIFYICONDATA, содержащую следующие поля:

• cbSize - размер данной структуры.
• hwnd - хэндл окна, которое будет получать уведомление, когда над иконкой в tray'e произойдёт событие мыши.
• uID - константа, используемая в качестве идентификатора иконки. Вы сами выбираете значение этой константе. В случае, если вы поместили в system tray несколько иконок, вы сможете узнать, над какой именно из них произошло событие мыши.
• uFlags - указывает, какие поля данной структуры заполнены

• NIF_ICON Поле hIcon заполнено.
• NIF_MESSAGE Поле uCallbackMessage заполнено.
• NIF_TIP Поле szTip заполнено.

• uCallbackMessage - пользовательское сообщение, которое Windows отошлёт указанному в поле hwnd окну, в случае, когда над иконкой произойдёт событие мыши. Сообщение вы создаете сами.
• hIcon - хэндл иконки, которую вы хотите поместить в system tray.
• szTip - 64-байтовый массив, содержащий строку для использования в качестве всплывающей подсказки к иконке.

• Вызовите Shell_NotifyIcon.inc. Данная функция имеет следующий синтаксис:
function Shell_NotifyIcon _
(byval dwMessage as DWORD, _
byval pnid as PNOTIFYICONDATA) as BOOL

• dwMessage - это тип сообщения, которое нужно отправить оболочке.

• NIM_ADD Добавляет иконку в system tray.
• NIM_DELETE Удаляет иконку из system tray.
• NIM_MODIFY Изменяет иконку в system tray.

• pnid - это указатель на коректно заполненную структуру NOTIFYICONDATA.

• Если вы хотите добавить иконку в system tray, используйте сообщение NIM_ADD, если хотите удалить иконку, применяйте NIM_DELETE.

Вот, собственно, и всё. Но чаще всего просто поместить иконку в system tray недостаточно. Вам нужно как-то реагировать на события мыши, происходящие над этой иконкой. Это можно сделать, обрабатывая сообщение, указанное в поле uCallbackMessage структуры NOTIFYICONDATA. Это сообщение содержит следующие значения
в wParam и lParam (отдельное спасибо s__d за эту информацию):

• wParam содержит ID иконки. Это то же самое значение, что вы поместили в поле uID структуры NOTIFYICONDATA.
• lParam Младшее слово содержит сообщение мыши. Например, если пользователь сделал правый щелчок по иконке, то lParam будет содержать WM_RBUTTONDOWN.

Обычно иконка в system tray показывает всплывающее меню при правом щелчке по ней. Этого можно добиться, если сначала создать само всплывающее меню, а затем вызывать TrackPopupMenu для его отображения. Шаги приведены ниже:

• Создайте всплывающее меню, вызвав CreatePopupMenu. Эта функция создаёт пустое меню, и при успешном создании возвращает его хэндл.
• Добавьте пункты в меню с помощью AppendMenu, InsertMenu или InsertMenuItem.
• Когда вам будет нужно отобразить всплывающее меню на месте курсора мыши, вызовите GetCursorPos, чтобы узнать текущие координаты курсора, а затем вызовите TrackPopupMenu, чтобы вывести меню на экран.
• Когда пользователь щёлкнет на одном из пунктов меню, Windows отправит сообщение WM_COMMAND вашей оконной процедуре, точно так же, как и при работе с обычным меню.

Внимание: остерегайтесь следующих проблем, часто возникающих при работе со всплывающими меню.

• Когда меню отображено на экране, щелчок вне меню не приводит к его немедленному исчезновению. Это происходит потому, что окно, которое будет получать уведомления от меню, ДОЛЖНО быть на переднем плане. Просто вызовите SetForegroundWindow, чтобы исправить эту проблему.
• После вызова SetForegroundWindow вы обнаружите, что в первый раз всплывающее меню сработает нормально, но при последующем появлении оно будет отображаться, а затем тут же исчезать. Как написано в MSDN, это сделано "намеренно". Необходимо переключить задачу на программу, являющуюся владельцем иконки в system tray. Этого можно добиться, отправив любое сообщение окну вашей программы. Но только используйте PostMessage, а не SendMessage!


Пример:

Код:

' system tray
#define WIN_INCLUDEALL
#include "windows.bi"

declare function WinMain ( byval hInst as HINSTANCE, _
byval hPrevInst as HINSTANCE, _
  byval szCmdLine as LPSTR, _
  byval iCmdShow as integer ) as integer


' начало программы
#define WM_SHELLNOTIFY WM_USER+5
#define IDI_TRAY 0
#define IDM_RESTORE 1000
#define IDM_EXIT 1010
#define ClassName "TrayIconWinClass" ' Имя нашего класса окна
#define AppName "TrayIcon Demo" ' Имя нашего окна
#define RestoreString "&Restore"
#define ExitString "E&xit Program"



dim shared hModule as HINSTANCE ' Хэндл нашей программы
dim shared hPopupMenu  as HMENU ' хэндл всплывающего меню
dim shared note as NOTIFYICONDATA ' структура NOTIFYICONDATA
hModule = GetModuleHandle( NULL ) ' Взять хэндл программы
end WinMain( hModule,NULL,GetCommandLine(), SW_SHOWNORMAL ) ' вызвать основную функцию
' здесь заканчивается программа

' процедура окна
function  WndProc _
(byval hwnd as HWND, _ ' хэндл окна
byval uMsg as UINT, _ ' сообщение
byval wParam as WPARAM, _ ' дополнительный  параметр сообщений
byval lParam as LPARAM) as LRESULT ' дополнительный параметр сообщений
dim pt as POINT ' абсолютные координаты мыши
function = 0
select case uMsg  'начинаем обработку сообщений
case WM_DESTROY ' если пользователь закрывает окно
    DestroyMenu(hPopupMenu) ' уничтожим меню
    PostQuitMessage(0) ' выходим из программы
exit function
case WM_CREATE ' если сообщение WM_CREATE
hPopupMenu = CreatePopupMenu() ' создадим всплывающее меню
AppendMenu _ ' добавим в меню
(hPopupMenu, _ ' хэндл меню
MF_STRING, _ ' строку
IDM_RESTORE, _ ' идентификатор меню
RestoreString) ' строка с названием пункта меню
AppendMenu _ ' добавим в меню
(hPopupMenu, _ ' хэндл меню
MF_STRING, _ ' строку
IDM_EXIT, _ ' идентификатор меню
ExitString) ' строка с названием пункта меню
case WM_SIZE ' если изменяется размер окна
if wParam = SIZE_MINIMIZED then ' если окно свернули
note.cbSize = sizeof(NOTIFYICONDATA) ' размер структуры NOTIFYICONDATA
note.hwnd = hWnd ' хэндл окна
note.uID = IDI_TRAY ' идентификатор трея
note.uFlags = NIF_ICON+NIF_MESSAGE+NIF_TIP ' флаги
note.uCallbackMessage = WM_SHELLNOTIFY ' сообщение от трея
note.hIcon = LoadIcon(NULL,IDI_WINLOGO) ' иконка
lstrcpy(note.szTip, AppName) ' текст в трее
ShowWindow _
(hWnd, _ ' хэндл окна
SW_HIDE) ' скроем окно
Shell_NotifyIcon _ ' в system tray
(NIM_ADD,_ ' добавить иконку
@note) ' указатель на структуру NOTIFYICONDATA
end if
case WM_COMMAND
if lParam = 0 then
Shell_NotifyIcon _
(NIM_DELETE, _ ' удалить иконку
@note) ' указатель на структуру NOTIFYICONDATA
select case loword(wParam)
case IDM_RESTORE  ' если выбрали Restore
ShowWindow _
(hWnd, _ ' хэндл окна
SW_RESTORE) ' восстановить окно
case IDM_EXIT
    DestroyWindow _ ' уничтожим окно
    (hWnd) ' хэндл окна
end select
end if
case WM_SHELLNOTIFY ' сообщение из трея
if wParam = IDI_TRAY then ' от нашей иконки
select case lParam
case WM_RBUTTONDOWN ' если нажали правую кнопку мыши
GetCursorPos _ ' получим позицию курсора
(@pt) ' указатель на структуру point
SetForegroundWindow _ ' установим окно на передний план
(hWnd) ' хэндл окна
TrackPopupMenu _ ' покажем всплывающее меню
(hPopupMenu, _ ' хэндл всплывающего меню
TPM_RIGHTALIGN, _ ' выровнять по правому краю
pt.x, _ ' координата x
pt.y, _ ' координата y
NULL, _
hWnd, _ ' хэндл окна
NULL)
PostMessage _ ' поместить сообщение
(hWnd, _ ' хэндл окна
WM_NULL, _ ' нулевое
0,0)
case WM_LBUTTONDBLCLK ' если нажали двойной клик левой кнопкой мыши
SendMessage _ ' пошлем сообщение
(hWnd, _ ' хэндл окна
WM_COMMAND, _
IDM_RESTORE, _ ' как будто мы нажали во всплывающем меню restore
0)
end select
end if
end select
function = DefWindowProc(hWnd,uMsg,wParam,lParam) ' Дефаултная функция обработки окна
end function

'функция WinMain
function WinMain _
(byval hInst as HINSTANCE, _ ' хэндл программы
byval hPrevInst as HINSTANCE, _ 'в win32 всегда 0
byval szCmdLine as LPSTR, _  'указатель на командную строку
byval iCmdShow as integer ) as integer  ' состояние окна при первом появлении

dim wc as WNDCLASSEX ' структура параметров окна
dim wMsg as MSG  ' структура сообщений
dim hWnd as HWND ' хэндл окна

 'структура класса окна wc
 ' заполняем структуру wc
wc.cbSize = SIZEOF( WNDCLASSEX )  ' размер структуры WNDCLASSEX
wc.style = CS_HREDRAW or CS_VREDRAW  ' Стиль окна
wc.lpfnWndProc = @WndProc ' Адрес процедуры окна WndProc
wc.cbClsExtra = NULL  ' резервирование  дополнительных байт за концом структуры
wc.cbWndExtra = NULL
wc.hInstance = hInst  ' хэндл модуля
wc.hbrBackground = cast(HGDIOBJ, COLOR_ApPWORKSPACE) ' Цвет фона
wc.lpszMenuName = NULL ' Хэндл меню
wc.lpszClassName = @ClassName ' класс окна
wc.hIcon = LoadIcon( NULL,IDI_APPLICATION ) ' Хэндл иконки
wc.hIconSm = wc.hIcon 'Хэндл маленькой иконки
wc.hCursor = LoadCursor( NULL,IDC_ARROW) ' Хэндл курсора


' регистрация нашего класса окна
if(RegisterClassEx(@wc) = FALSE) then
MessageBox(0,"Не могу зарегистрировать класс окна","Ошибка",0)
end 1
end if

' Создадим окно
hwnd = CreateWindowEx _
(WS_EX_CLIENTEDGE, _ ' дополнительные стили
@ClassName, _ ' указатель на строку с именем класса окна
@AppName, _ ' указатель на строку с именем окна
WS_OVERLAPPED+WS_CAPTION+WS_SYSMENU+WS_MINIMIZEBOX+WS_MAXIMIZEBOX+WS_VISIBLE, _ ' стиль окна
CW_USEDEFAULT, _ ' X
CW_USEDEFAULT, _ ' Y
350, _ ' ширина окна
200, _ ' высота окна
NULL, _ ' хэндл родительского окна
NULL, _ ' хэндл меню
hInst, _ ' хэндл модуля
NULL) ' указатель на структуру данных
while( GetMessage( @wMsg, NULL, 0, 0 ) <> FALSE )  'цикл сообщений
TranslateMessage( @wMsg )
DispatchMessage( @wMsg )
wend
function = wMsg.wParam
end function


Последний раз редактировалось: electrik (Вт Май 23, 2017 5:27 pm), всего редактировалось 1 раз(а)

electrik

Сообщения : 391
Дата регистрации : 2008-09-02
Возраст : 36
Откуда : галактика Млечный путь, система Солнечная, планета Земля, страна россия, город Санкт Петербург

Посмотреть профиль

Вернуться к началу Перейти вниз

Re: платформа Win32 - Туториалы Iczelion'a на русском, адаптированные для FreeBasic. Урок 23 - Иконка в system tray

Сообщение  electrik в Вт Июн 30, 2009 7:11 pm

Win32 API. Урок 23. Иконка в system tray - продолжение

Анализ:

Программа отобразит на экране обычное окно. По нажатию кнопки "Свернуть" оно свернётся до иконки в system tray По двойному щелчку по иконке программа восстановит своё окно и удалит иконку из system tray. По правому щелчку будет выведено всплывающее меню, из которого можно восстановить программу или выйти из неё.

case WM_CREATE
hPopupMenu = CreatePopupMenu()
AppendMenu _
(hPopupMenu, _
MF_STRING, _
IDM_RESTORE, _
RestoreString)
AppendMenu _
(hPopupMenu, _
MF_STRING, _
IDM_EXIT, _
ExitString)

Когда будет создано главное окно, также создастся всплывающее меню, к которому затем будут добавлены два пункта. Функция AppendMenu имеет следующий синтаксис:

function AppendMenu _
(byval hMenu as HMENU, _
byval uFlags as UINT, _
byval uIDNewItem as UINT_PTR, _
byval lpNewItem as LPCSTR) as BOOL

• hMenu это хэндл меню, к которому вы хотите добавить пункт
• uFlags информирует Windows о добавляемом пункте меню - изображение ли это, строка или отрисовываемый владельцем объект; включен ли он, неопределён или отключен, и т.д. Полный список есть в win32 api reference. В нашем случае мы используем флаг MF_STRING, который означает, что пункт меню - это строка.
• uIDNewItem это ID пункта меню. Это значение определяется пользователем, и используется для обращения к пункту меню.
• lpNewItem хранит содержание пункта меню, в зависимости от значения поля uFlags. Так как мы указали MF_STRING в поле uFlags, то lpNewItem должен содержать указатель на строку для отображения в пункте меню.

После того, как всплывающее меню создано, главное окно будет терпеливо ждать до тех пор, пока пользователь не нажмёт на кнопку "Свернуть".

Когда окно сворачивается, оно получает сообщение WM_SIZE со значением SIZE_MINIMIZED в wParam.

case WM_SIZE
if wParam = SIZE_MINIMIZED then
note.cbSize = sizeof(NOTIFYICONDATA)
note.hwnd = hWnd
note.uID = IDI_TRAY
note.uFlags = NIF_ICON+NIF_MESSAGE+NIF_TIP
note.uCallbackMessage = WM_SHELLNOTIFY
note.hIcon = LoadIcon(NULL,IDI_WINLOGO)
lstrcpy(note.szTip, AppName)
ShowWindow _
(hWnd, _
SW_HIDE)
Shell_NotifyIcon _ '
(NIM_ADD,_
@note)
end if

Мы используем этот момент, чтобы заполнить структуру NOTIFYICONDATA. IDI_TRAY это просто константа, определённая в начале исходного кода. Ей можно задать любое значение. Это не очень важно, так как у нас только одна иконка в system tray. Но если вы захотите поместить туда сразу несколько иконок, то вам потребуется задать уникальный ID для каждой из них. Мы выставляем сразу все флаги в поле uFlags, так как мы указываем иконку (NIF_ICON), мы указываем пользовательское сообщение (NIF_MESSAGE), а также текст всплывающей подсказки (NIF_TIP). WM_SHELLNOTIFY это просто пользовательское сообщение, определённое как WM_USER+5.
Само значение не так важно, пока оно сохраняет свою уникальность. Я использовал логотип Windows в качестве иконки для этой программы, но вы можете использовать и любую другую иконку Wink Просто загрузите её из файла ресурсов вызовом LoadIcon и сохраните возвращаемое значение в поле hIcon. После всего этого поместим в поле szTip текст, который мы хотим видеть в качестве всплывающей подсказки к иконке.

Мы скрываем главное окно, чтобы создать эффект "сворачивания в иконку". Затем мы вызываем Shell_NotifyIcon с сообщением NIM_ADD, чтобы добавить иконку в system tray.

Теперь наше главное окно скрыто, а иконка успешно помещена в system tray. Если вы наведёте на неё курсор, то увидите подсказку с текстом, который вы поместили в поле szTip. Далее, если вы дважды щелкните по иконке, восстановится главное окно, а сама иконка исчезнет.

case WM_SHELLNOTIFY
if wParam = IDI_TRAY then
select case lParam
case WM_RBUTTONDOWN
GetCursorPos _
(@pt)
SetForegroundWindow _
(hWnd)
TrackPopupMenu _
(hPopupMenu, _
TPM_RIGHTALIGN, _
pt.x, _
pt.y, _
NULL, _
hWnd, _
NULL)
PostMessage _
(hWnd, _
WM_NULL, _ ' нулевое
0,0)
case WM_LBUTTONDBLCLK ' если нажали двойной клик левой кнопкой мыши
SendMessage _
(hWnd, _
WM_COMMAND, _
IDM_RESTORE, _
0)

Когда над иконкой происходит событие мыши, ваше окно получает сообщение WM_SHELLNOTIFY, то есть пользовательское сообщение, указанное в поле uCallbackMessage.
Напомню, что по приёму этого сообщения wParam содержит ID иконки, а lParam содержит событие мыши. В вышеприведенном коде сначала проверяется, пришло ли сообщение от интересующей нас иконки. Если да, то тогда мы смотрим на событие мыши. Так как нам нужны только правый щелчок и левый двойной щелчок, то мы обрабатываем лишь сообщения WM_RBUTTONDOWN и WM_LBUTTONDBLCLK.

Если сообщение от мыши это WM_RBUTTONDOWN, мы вызываем GetCursorPos, чтобы узнать текущие координаты курсора мыши. После возврата из функции, структура POINT содержит абсолютные координаты курсора. Под абсолютными координатами я подразумеваю координаты, привязанные ко всему экрану, не берущие во внимание границы окна. Например, если разрешение экрана 640*480, то правый нижний угол это x==639, y==479. Если вы желаете перевести абсолютные координаты в оконные, используйте функцию ScreenToClient.

Однако мы хотим отобразить всплывающее меню в точке, где сейчас расположен курсор мыши, с помощью функции TrackPopupMenu, которой требуются именно абсолютные координаты. Поэтому мы просто используем координаты, полученные от GetCursorPos.

TrackPopupMenu имеет следующий синтаксис:

function TrackPopupMenu _
(byval hMenu as HMENU, _
byval uFlags as UINT, _
byval x as integer, _
byval y as integer, _
byval nReserved as integer, _
byval hWnd as HWND, _
byval prcRect as LPCRECT) as BOOL

• hMenu это хэндл всплывающего меню, которое нужно отобразить.
• uFlags указывает опции отображения. Например, как располагать меню относительно указанных ниже координат, и какая из кнопок мыши используется для отслеживания меню. В нашем примере мы используем флаг TPM_RIGHTALIGN, чтобы разместить меню слева от указанной точки.
• x и y указывают местоположение меню в абсолютных координатах.
• nReserved должно содержать NULL.
• hWnd это хэндл окна, которое будет получать сообщения от меню.
• prcRect это прямоугольная область экрана, щелчки в пределах которой НЕ будут приводить к исчезновению меню. Обычно сюда помещается NULL, чтобы меню исчезало при любом щелчке вне его.

Когда пользователь дважды щелкнет по иконке, мы отправим нашему окну сообщение WM_COMMAND с указанием IDM_RESTORE, чтобы создать иллюзию выбора пользователем пункта "Восстановить" в меню, и таким образом восстановить окно, а также удалить иконку из system tray. Чтобы иметь возможность получать сообщения двойного щелчка, главное окно должно иметь стиль CS_DBLCLKS.

Shell_NotifyIcon _
(NIM_DELETE, _
@note)
select case loword(wParam)
case IDM_RESTORE
ShowWindow _
(hWnd, _
SW_RESTORE)
case IDM_EXIT
DestroyWindow _
(hWnd)

Когда пользователь выберет пункт "Восстановить" в меню, мы удаляем иконку повторным вызовом Shell_NotifyIcon, только на этот раз указывая NIM_DELETE в качестве сообщения. Затем мы возвращаем первозданный вид главному окну. Если пользователь выберет пункт "Закрыть", мы тоже удаляем иконку из system tray и уничтожаем главное окно вызовом DestroyWindow.

[C] Iczelion, пер. WD-40.

electrik

Сообщения : 391
Дата регистрации : 2008-09-02
Возраст : 36
Откуда : галактика Млечный путь, система Солнечная, планета Земля, страна россия, город Санкт Петербург

Посмотреть профиль

Вернуться к началу Перейти вниз

Re: платформа Win32 - Туториалы Iczelion'a на русском, адаптированные для FreeBasic. Урок 23 - Иконка в system tray

Сообщение  electrik в Вт Июн 30, 2009 7:14 pm

напомню, что примеры к 23 tutorial'ам можно скачать:
http://www.filehoster.ru/files/da3601
продолжение скоро будет. как только обработаю урок, сразу буду выкладывать.

electrik

Сообщения : 391
Дата регистрации : 2008-09-02
Возраст : 36
Откуда : галактика Млечный путь, система Солнечная, планета Земля, страна россия, город Санкт Петербург

Посмотреть профиль

Вернуться к началу Перейти вниз

Re: платформа Win32 - Туториалы Iczelion'a на русском, адаптированные для FreeBasic. Урок 23 - Иконка в system tray

Сообщение  Спонсируемый контент


Спонсируемый контент


Вернуться к началу Перейти вниз

Предыдущая тема Следующая тема Вернуться к началу


 
Права доступа к этому форуму:
Вы не можете отвечать на сообщения