对TrackPopupMenu不懂(100分)

  • 主题发起人 主题发起人 DDK
  • 开始时间 开始时间
D

DDK

Unregistered / Unconfirmed
GUEST, unregistred user!
我有一个小程序,把图标缩小到任务栏上后,点右键CreateMenu,再调用trackpopupMenu,<br>菜单是出来,可是我点到菜单以外的地方,菜单并不消失。
 
给你一段代码你可以看看<br><br>unit ADTrayIcon;<br><br>interface<br><br>uses<br>&nbsp; Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,<br>&nbsp; Menus, ShellApi, ExtCtrls;<br><br>const<br>&nbsp; { Define user-defined message sent by the trayicon. We avoid low user-defined<br>&nbsp; &nbsp; messages that are used by Windows itself (eg. WM_USER+1 = DM_SETDEFID). }<br>&nbsp; WM_TRAYNOTIFY = WM_USER + 1024;<br>&nbsp; // Constant used for recreating trayicon on system traybar recover<br>&nbsp; IconID = 1;<br>&nbsp; // Constants used for balloon hint feature<br>&nbsp; WM_RESETTOOLTIP = WM_USER + 1025;<br>&nbsp; NIIF_NONE &nbsp; &nbsp;= $00000000;<br>&nbsp; NIIF_INFO &nbsp; &nbsp;= $00000001;<br>&nbsp; NIIF_WARNING = $00000002;<br>&nbsp; NIIF_ERROR &nbsp; = $00000003;<br>&nbsp; NIF_INFO &nbsp; &nbsp; = $00000010;<br><br>var<br>&nbsp; WM_TASKBARCREATED: Cardinal;<br><br>type<br>&nbsp; { You can use the TNotifyIconData record structure defined in shellapi.pas.<br>&nbsp; &nbsp; However, WinME, Win2000, and WinXP have expanded this structure. We define<br>&nbsp; &nbsp; a similar structure, TNotifyIconDataEx. }<br>&nbsp; TNotifyIconDataEx = record<br>&nbsp; &nbsp; cbSize: DWORD;<br>&nbsp; &nbsp; Wnd: HWND;<br>&nbsp; &nbsp; uID: UINT;<br>&nbsp; &nbsp; uFlags: UINT;<br>&nbsp; &nbsp; uCallbackMessage: UINT;<br>&nbsp; &nbsp; hIcon: HICON;<br>// &nbsp; &nbsp;szTip: array[0..63] of AnsiChar;<br>&nbsp; &nbsp; szTip: array[0..127] of AnsiChar;<br>&nbsp; &nbsp; dwState: DWORD;<br>&nbsp; &nbsp; dwStateMask: DWORD;<br>&nbsp; &nbsp; szInfo: array[0..255] of AnsiChar;<br>&nbsp; &nbsp; uTimeout: UINT; // union with uVersion: UINT;<br>&nbsp; &nbsp; szInfoTitle: array[0..63] of AnsiChar;<br>&nbsp; &nbsp; dwInfoFlags: DWORD;<br>&nbsp; end;<br><br>&nbsp; TBalloonHintIcon = (bitNone, bitInfo, bitWarning, bitError);<br>&nbsp; TBalloonHintTimeOut = 10..60; &nbsp; // Windows defines 10-60 secs. as min-max<br><br>&nbsp; TCycleEvent = procedure(Sender: TObject; NextIndex: Integer) of object;<br><br>&nbsp; TADTrayIcon = class(TComponent)<br>&nbsp; private<br>&nbsp; &nbsp; FEnabled: Boolean;<br>&nbsp; &nbsp; FIcon: TIcon;<br>&nbsp; &nbsp; FIconVisible: Boolean;<br>&nbsp; &nbsp; FHint: String;<br>&nbsp; &nbsp; FPopupMenu: TPopupMenu;<br>&nbsp; &nbsp; FLeftPopup: Boolean;<br>&nbsp; &nbsp; FOnClick,<br>&nbsp; &nbsp; FOnDblClick: TNotifyEvent;<br>&nbsp; &nbsp; FOnCycle: TCycleEvent;<br>&nbsp; &nbsp; FOnMouseDown,<br>&nbsp; &nbsp; FOnMouseUp: TMouseEvent;<br>&nbsp; &nbsp; FOnMouseMove: TMouseMoveEvent;<br>&nbsp; &nbsp; FClickStart: Boolean;<br>&nbsp; &nbsp; CycleTimer: TTimer; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // For icon cycling<br>&nbsp; &nbsp; FIconIndex: Integer; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;// Current index in imagelist<br>&nbsp; &nbsp; FDesignPreview: Boolean;<br>&nbsp; &nbsp; SettingPreview: Boolean;<br>&nbsp; &nbsp; FIconList: TImageList;<br>&nbsp; &nbsp; FCycleIcons: Boolean;<br>&nbsp; &nbsp; FCycleInterval: Cardinal;<br>&nbsp; &nbsp; OldAppProc, NewAppProc: Pointer; &nbsp; // Procedure variables<br>&nbsp; &nbsp; FWindowHandle: HWND; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // Window handle (not general handle)<br>&nbsp; &nbsp; procedure SetCycleIcons(Value: Boolean);<br>&nbsp; &nbsp; procedure SetDesignPreview(Value: Boolean);<br>&nbsp; &nbsp; procedure SetCycleInterval(Value: Cardinal);<br>&nbsp; &nbsp; procedure TimerCycle(Sender: TObject);<br>&nbsp; &nbsp; procedure HandleIconMessage(var Msg: TMessage);<br>&nbsp; &nbsp; function InitIcon: Boolean;<br>&nbsp; &nbsp; procedure SetIcon(Value: TIcon);<br>&nbsp; &nbsp; procedure SetIconVisible(Value: Boolean);<br>&nbsp; &nbsp; procedure SetIconList(Value: TImageList);<br>&nbsp; &nbsp; procedure SetIconIndex(Value: Integer);<br>&nbsp; &nbsp; procedure SetHint(Value: String);<br>&nbsp; &nbsp; procedure PopupAtCursor;<br>&nbsp; &nbsp; procedure HookApp;<br>&nbsp; &nbsp; procedure UnhookApp;<br>&nbsp; &nbsp; procedure HookAppProc(var Msg: TMessage);<br>&nbsp; protected<br>&nbsp; &nbsp; IconData: TNotifyIconDataEx; &nbsp; &nbsp;// Data of the tray icon wnd.<br>&nbsp; &nbsp; procedure Loaded; override;<br>&nbsp; &nbsp; function ShowIcon: Boolean; virtual;<br>&nbsp; &nbsp; function HideIcon: Boolean; virtual;<br>&nbsp; &nbsp; function ModifyIcon: Boolean; virtual;<br>&nbsp; &nbsp; procedure Click; dynamic;<br>&nbsp; &nbsp; procedure DblClick; dynamic;<br>&nbsp; &nbsp; procedure CycleIcon; dynamic;<br>&nbsp; &nbsp; procedure MouseDown(Button: TMouseButton; Shift: TShiftState;<br>&nbsp; &nbsp; &nbsp; X, Y: Integer); dynamic;<br>&nbsp; &nbsp; procedure MouseUp(Button: TMouseButton; Shift: TShiftState;<br>&nbsp; &nbsp; &nbsp; X, Y: Integer); dynamic;<br>&nbsp; &nbsp; procedure MouseMove(Shift: TShiftState; X, Y: Integer); dynamic;<br>&nbsp; &nbsp; procedure Notification(AComponent: TComponent; Operation: TOperation);<br>&nbsp; &nbsp; &nbsp; override;<br>&nbsp; public<br>{$IFDEF DFS_CPPB_3_UP}<br>&nbsp; &nbsp; property Handle: HWND read IconData.hWnd;<br>{$ELSE}<br>&nbsp; &nbsp; property Handle: HWND read IconData.Wnd;<br>{$ENDIF}<br>&nbsp; &nbsp; property WindowHandle: HWND read FWindowHandle;<br>&nbsp; &nbsp; constructor Create(AOwner: TComponent); override;<br>&nbsp; &nbsp; destructor Destroy; override;<br>&nbsp; &nbsp; procedure Refresh;<br>&nbsp; &nbsp; function ShowBalloonHint(Title: String; Text: String; IconType: TBalloonHintIcon;<br>&nbsp; &nbsp; &nbsp; TimeoutSecs: TBalloonHintTimeOut): Boolean;<br>&nbsp; published<br>&nbsp; &nbsp; // Properties:<br>&nbsp; &nbsp; property DesignPreview: Boolean read FDesignPreview<br>&nbsp; &nbsp; &nbsp; write SetDesignPreview default False;<br>&nbsp; &nbsp; property IconList: TImageList read FIconList write SetIconList;<br>&nbsp; &nbsp; property CycleIcons: Boolean read FCycleIcons write SetCycleIcons<br>&nbsp; &nbsp; &nbsp; default False;<br>&nbsp; &nbsp; property CycleInterval: Cardinal read FCycleInterval<br>&nbsp; &nbsp; &nbsp; write SetCycleInterval;<br>&nbsp; &nbsp; property Enabled: Boolean read FEnabled write FEnabled default True;<br>&nbsp; &nbsp; property Hint: String read FHint write SetHint;<br>&nbsp; &nbsp; property Icon: TIcon read FIcon write SetIcon stored True;<br>&nbsp; &nbsp; property IconVisible: Boolean read FIconVisible write SetIconVisible<br>&nbsp; &nbsp; &nbsp; default True;<br>&nbsp; &nbsp; property IconIndex: Integer read FIconIndex write SetIconIndex;<br>&nbsp; &nbsp; property PopupMenu: TPopupMenu read FPopupMenu write FPopupMenu;<br>&nbsp; &nbsp; property LeftPopup: Boolean read FLeftPopup write FLeftPopup<br>&nbsp; &nbsp; &nbsp; default False;<br>&nbsp; &nbsp; property OnClick: TNotifyEvent read FOnClick write FOnClick;<br>&nbsp; &nbsp; property OnDblClick: TNotifyEvent read FOnDblClick write FOnDblClick;<br>&nbsp; &nbsp; property OnMouseDown: TMouseEvent read FOnMouseDown write FOnMouseDown;<br>&nbsp; &nbsp; property OnMouseUp: TMouseEvent read FOnMouseUp write FOnMouseUp;<br>&nbsp; &nbsp; property OnMouseMove: TMouseMoveEvent read FOnMouseMove write FOnMouseMove;<br>&nbsp; &nbsp; property OnCycle: TCycleEvent read FOnCycle write FOnCycle;<br>&nbsp; end;<br><br>procedure Register;<br><br>implementation<br><br>{--------------------- TADTrayIcon ----------------------}<br><br>constructor TADTrayIcon.Create(AOwner: TComponent);<br>begin<br>&nbsp; inherited Create(AOwner);<br>&nbsp; FIconVisible := True; &nbsp; &nbsp; &nbsp;// Visible by default<br>&nbsp; FEnabled := True; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;// Enabled by default<br>&nbsp; SettingPreview := False;<br><br>&nbsp; // Use the TaskbarCreated message available from Win98/IE4+<br>&nbsp; WM_TASKBARCREATED := RegisterWindowMessage('TaskbarCreated');<br><br>&nbsp; FIcon := TIcon.Create;<br>&nbsp; IconData.cbSize := SizeOf(TNotifyIconDataEx);<br>&nbsp; // IconData.wnd points to procedure to receive callback messages from the icon<br>&nbsp; IconData.wnd := AllocateHWnd(HandleIconMessage);<br>&nbsp; // Add an id for the tray icon<br>&nbsp; IconData.uId := IconID;<br>&nbsp; // We want icon, message handling, and tooltips by default<br>&nbsp; IconData.uFlags := NIF_ICON + NIF_MESSAGE + NIF_TIP;<br>&nbsp; // Message to send to IconData.wnd when event occurs<br>&nbsp; IconData.uCallbackMessage := WM_TRAYNOTIFY;<br><br>&nbsp; FWindowHandle := GetWindowLong(IconData.wnd, GWL_HWNDPARENT);<br><br>&nbsp; CycleTimer := TTimer.Create(Self);<br>&nbsp; CycleTimer.Enabled := False;<br>&nbsp; CycleTimer.Interval := FCycleInterval;<br>&nbsp; CycleTimer.OnTimer := TimerCycle;<br><br>&nbsp; // Hook into the app.'s message handling<br>&nbsp; if not (csDesigning in ComponentState) then<br>&nbsp; &nbsp; HookApp;<br>end;<br><br><br>destructor TADTrayIcon.Destroy;<br>begin<br>&nbsp; SetIconVisible(False); &nbsp; &nbsp; // Remove the icon from the tray<br>&nbsp; FIcon.Free; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;// Free the icon<br>&nbsp; DeallocateHWnd(IconData.Wnd); &nbsp; // Free the tray window<br>&nbsp; CycleTimer.Free;<br>&nbsp; // It is important to unhook any hooked processes<br>&nbsp; if not (csDesigning in ComponentState) then<br>&nbsp; &nbsp; UnhookApp;<br>&nbsp; inherited Destroy;<br>end;<br><br><br>procedure TADTrayIcon.Loaded;<br>{ This method is called when all properties of the component have been<br>&nbsp; initialized. The method SetIconVisible must be called here, after the<br>&nbsp; tray icon (FIcon) has loaded itself. Otherwise, the tray icon will<br>&nbsp; be blank (no icon image). }<br>begin<br>&nbsp; inherited Loaded; &nbsp; &nbsp; // Always call inherited Loaded first<br>&nbsp; ModifyIcon;<br>&nbsp; SetIconVisible(FIconVisible);<br>end;<br><br><br>procedure TADTrayIcon.Notification(AComponent: TComponent;<br>&nbsp; Operation: TOperation);<br>begin<br>&nbsp; inherited Notification(AComponent, Operation);<br>&nbsp; { Check if either the imagelist or the popup menu is about<br>&nbsp; &nbsp; to be deleted }<br>&nbsp; if (AComponent = IconList) and (Operation = opRemove) then<br>&nbsp; begin<br>&nbsp; &nbsp; FIconList := nil;<br>&nbsp; &nbsp; IconList := nil;<br>&nbsp; end;<br>&nbsp; if (AComponent = PopupMenu) and (Operation = opRemove) then<br>&nbsp; begin<br>&nbsp; &nbsp; FPopupMenu := nil;<br>&nbsp; &nbsp; PopupMenu := nil;<br>&nbsp; end;<br>end;<br><br><br>{ For MinimizeToTray to work, we need to know when the form is minimized<br>&nbsp; (happens when either the application or the main form minimizes).<br>&nbsp; The straight-forward way is to make TADTrayIcon trap the<br>&nbsp; Application.OnMinimize event. However, if you also make use of this<br>&nbsp; event in the application, the OnMinimize code used by TADTrayIcon<br>&nbsp; is discarded.<br>&nbsp; The alternative is to hook into the app.'s message handling (via<br>&nbsp; HookApp). You can then catch any message that goes through the app.<br>&nbsp; and still use the OnMinimize event. }<br><br>procedure TADTrayIcon.HookApp;<br>begin<br>&nbsp; // Hook the application<br>&nbsp; OldAppProc := Pointer(GetWindowLong(Application.Handle, GWL_WNDPROC));<br>&nbsp; NewAppProc := MakeObjectInstance(HookAppProc);<br>&nbsp; SetWindowLong(Application.Handle, GWL_WNDPROC, LongInt(NewAppProc));<br>end;<br><br><br>procedure TADTrayIcon.UnhookApp;<br>begin<br>&nbsp; if Assigned(OldAppProc) then<br>&nbsp; &nbsp; SetWindowLong(Application.Handle, GWL_WNDPROC, LongInt(OldAppProc));<br>&nbsp; if Assigned(NewAppProc) then<br>&nbsp; &nbsp; FreeObjectInstance(NewAppProc);<br>&nbsp; NewAppProc := nil;<br>&nbsp; OldAppProc := nil;<br>end;<br><br><br>{ All app. messages pass through HookAppProc. You can override the<br>&nbsp; messages by not passing them along to Windows (via CallWindowProc). }<br><br>procedure TADTrayIcon.HookAppProc(var Msg: TMessage);<br>begin<br><br>&nbsp; { Show the tray icon if the taskbar has been re-created after an<br>&nbsp; &nbsp; Explorer crash. }<br>&nbsp; if Msg.Msg = WM_TASKBARCREATED then<br>&nbsp; &nbsp; if FIconVisible then<br>&nbsp; &nbsp; &nbsp; ShowIcon;<br><br>&nbsp; // Pass the message on<br>&nbsp; Msg.Result := CallWindowProc(OldAppProc, Application.Handle,<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Msg.Msg, Msg.wParam, Msg.lParam);<br>end;<br><br><br>{ HandleIconMessage handles messages that go to the shell notification<br>&nbsp; window (tray icon) itself. Most messages are passed through WM_TRAYNOTIFY.<br>&nbsp; In these cases use lParam to get the actual message, eg. WM_MOUSEMOVE.<br>&nbsp; The method sends the usual Delphi events for the mouse messages. It also<br>&nbsp; interpolates the OnClick event when the user clicks the left button, and<br>&nbsp; makes the menu (if any) popup on left and right mouse down events. }<br><br>procedure TADTrayIcon.HandleIconMessage(var Msg: TMessage);<br><br>&nbsp; function ShiftState: TShiftState;<br>&nbsp; // Return the state of the shift, ctrl, and alt keys<br>&nbsp; begin<br>&nbsp; &nbsp; Result := [];<br>&nbsp; &nbsp; if GetAsyncKeyState(VK_SHIFT) &lt; 0 then<br>&nbsp; &nbsp; &nbsp; Include(Result, ssShift);<br>&nbsp; &nbsp; if GetAsyncKeyState(VK_CONTROL) &lt; 0 then<br>&nbsp; &nbsp; &nbsp; Include(Result, ssCtrl);<br>&nbsp; &nbsp; if GetAsyncKeyState(VK_MENU) &lt; 0 then<br>&nbsp; &nbsp; &nbsp; Include(Result, ssAlt);<br>&nbsp; end;<br><br>var<br>&nbsp; Pt: TPoint;<br>&nbsp; Shift: TShiftState;<br>&nbsp; I: Integer;<br>&nbsp; M: TMenuItem;<br>begin<br>&nbsp; if Msg.Msg = WM_TRAYNOTIFY then<br>&nbsp; // Take action if a message from the icon comes through<br>&nbsp; begin<br>&nbsp; &nbsp; case Msg.lParam of<br><br>&nbsp; &nbsp; &nbsp; WM_MOUSEMOVE:<br>&nbsp; &nbsp; &nbsp; &nbsp; if FEnabled then<br>&nbsp; &nbsp; &nbsp; &nbsp; begin<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Shift := ShiftState;<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; GetCursorPos(Pt);<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; MouseMove(Shift, Pt.X, Pt.Y);<br>&nbsp; &nbsp; &nbsp; &nbsp; end;<br><br>&nbsp; &nbsp; &nbsp; WM_LBUTTONDOWN:<br>&nbsp; &nbsp; &nbsp; &nbsp; if FEnabled then<br>&nbsp; &nbsp; &nbsp; &nbsp; begin<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Shift := ShiftState + [ssLeft];<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; GetCursorPos(Pt);<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; MouseDown(mbLeft, Shift, Pt.X, Pt.Y);<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; FClickStart := True;<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if FLeftPopup then<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; PopupAtCursor;<br>&nbsp; &nbsp; &nbsp; &nbsp; end;<br><br>&nbsp; &nbsp; &nbsp; WM_RBUTTONDOWN:<br>&nbsp; &nbsp; &nbsp; &nbsp; if FEnabled then<br>&nbsp; &nbsp; &nbsp; &nbsp; begin<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Shift := ShiftState + [ssRight];<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; GetCursorPos(Pt);<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; MouseDown(mbRight, Shift, Pt.X, Pt.Y);<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; PopupAtCursor;<br>&nbsp; &nbsp; &nbsp; &nbsp; end;<br><br>&nbsp; &nbsp; &nbsp; WM_MBUTTONDOWN:<br>&nbsp; &nbsp; &nbsp; &nbsp; if FEnabled then<br>&nbsp; &nbsp; &nbsp; &nbsp; begin<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Shift := ShiftState + [ssMiddle];<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; GetCursorPos(Pt);<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; MouseDown(mbMiddle, Shift, Pt.X, Pt.Y);<br>&nbsp; &nbsp; &nbsp; &nbsp; end;<br><br>&nbsp; &nbsp; &nbsp; WM_LBUTTONUP:<br>&nbsp; &nbsp; &nbsp; &nbsp; if FEnabled then<br>&nbsp; &nbsp; &nbsp; &nbsp; begin<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Shift := ShiftState + [ssLeft];<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; GetCursorPos(Pt);<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if FClickStart then &nbsp; &nbsp; &nbsp; // Then WM_LBUTTONDOWN was called before<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; begin<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; FClickStart := False;<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Click; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;// We have a click<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; end;<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; MouseUp(mbLeft, Shift, Pt.X, Pt.Y);<br>&nbsp; &nbsp; &nbsp; &nbsp; end;<br><br>&nbsp; &nbsp; &nbsp; WM_RBUTTONUP:<br>&nbsp; &nbsp; &nbsp; &nbsp; if FEnabled then<br>&nbsp; &nbsp; &nbsp; &nbsp; begin<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Shift := ShiftState + [ssRight];<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; GetCursorPos(Pt);<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; MouseUp(mbRight, Shift, Pt.X, Pt.Y);<br>&nbsp; &nbsp; &nbsp; &nbsp; end;<br><br>&nbsp; &nbsp; &nbsp; WM_MBUTTONUP:<br>&nbsp; &nbsp; &nbsp; &nbsp; if FEnabled then<br>&nbsp; &nbsp; &nbsp; &nbsp; begin<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Shift := ShiftState + [ssMiddle];<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; GetCursorPos(Pt);<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; MouseUp(mbMiddle, Shift, Pt.X, Pt.Y);<br>&nbsp; &nbsp; &nbsp; &nbsp; end;<br><br>&nbsp; &nbsp; &nbsp; WM_LBUTTONDBLCLK:<br>&nbsp; &nbsp; &nbsp; &nbsp; if FEnabled then<br>&nbsp; &nbsp; &nbsp; &nbsp; begin<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; DblClick;<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; { Handle default menu items. But only if LeftPopup is false,<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; or it will conflict with the popupmenu, when it is called<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; by a click event. }<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; M := nil;<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if Assigned(FPopupMenu) then<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (FPopupMenu.AutoPopup) and (not FLeftPopup) then<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; for I := PopupMenu.Items.Count -1 downto 0 do<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; begin<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if PopupMenu.Items.Default then<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; M := PopupMenu.Items;<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; end;<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if M &lt;&gt; nil then<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; M.Click;<br>&nbsp; &nbsp; &nbsp; &nbsp; end;<br>&nbsp; &nbsp; &nbsp; end;<br>&nbsp; end<br><br>&nbsp; else &nbsp; &nbsp; &nbsp; &nbsp;// Messages that didn't go through the icon<br>&nbsp; &nbsp; case Msg.Msg of<br>&nbsp; &nbsp; &nbsp; { Windows sends us a WM_QUERYENDSESSION message when it prepares<br>&nbsp; &nbsp; &nbsp; &nbsp; for shutdown. Msg.Result must not return 0, or the system will<br>&nbsp; &nbsp; &nbsp; &nbsp; be unable to shut down. }<br>&nbsp; &nbsp; &nbsp; WM_QUERYENDSESSION: begin<br>//showmessage('WM_QUERYENDSESSION');<br>// &nbsp; &nbsp; &nbsp; &nbsp;PostQuitMessage(0);<br>&nbsp; &nbsp; &nbsp; &nbsp; Msg.Result := 1;<br>&nbsp; &nbsp; &nbsp; end;<br>{<br>&nbsp; &nbsp; &nbsp; WM_DESTROY: begin<br>showmessage('WM_DESTROY');<br>&nbsp; &nbsp; &nbsp; &nbsp; PostQuitMessage(0);<br>&nbsp; &nbsp; &nbsp; &nbsp; Msg.Result := 0;<br>&nbsp; &nbsp; &nbsp; end;<br>}<br>{<br>&nbsp; &nbsp; &nbsp; WM_ENDSESSION: begin<br>//showmessage('WM_ENDSESSION');<br>&nbsp; &nbsp; &nbsp; &nbsp; Msg.Result := 0;<br>&nbsp; &nbsp; &nbsp; end;<br>}<br>&nbsp; &nbsp; else &nbsp; &nbsp; &nbsp;// Handle all other messages with the default handler<br>&nbsp; &nbsp; &nbsp; Msg.Result := DefWindowProc(IconData.Wnd, Msg.Msg, Msg.wParam, Msg.lParam);<br>&nbsp; &nbsp; end;<br>end;<br><br><br>procedure TADTrayIcon.SetIcon(Value: TIcon);<br>begin<br>&nbsp; FIcon.Assign(Value);<br>&nbsp; ModifyIcon;<br>end;<br><br><br>procedure TADTrayIcon.SetIconVisible(Value: Boolean);<br>begin<br>&nbsp; if Value then<br>&nbsp; &nbsp; ShowIcon<br>&nbsp; else<br>&nbsp; &nbsp; HideIcon;<br>end;<br><br><br>procedure TADTrayIcon.SetDesignPreview(Value: Boolean);<br>begin<br>&nbsp; FDesignPreview := Value;<br>&nbsp; SettingPreview := True; &nbsp; &nbsp; &nbsp; &nbsp; // Raise flag<br>&nbsp; SetIconVisible(Value);<br>&nbsp; SettingPreview := False; &nbsp; &nbsp; &nbsp; &nbsp;// Clear flag<br>end;<br><br><br>procedure TADTrayIcon.SetCycleIcons(Value: Boolean);<br>begin<br>&nbsp; FCycleIcons := Value;<br>&nbsp; if Value then<br>&nbsp; &nbsp; SetIconIndex(0);<br>&nbsp; CycleTimer.Enabled := Value;<br>end;<br><br><br>procedure TADTrayIcon.SetCycleInterval(Value: Cardinal);<br>begin<br>&nbsp; FCycleInterval := Value;<br>&nbsp; CycleTimer.Interval := FCycleInterval;<br>end;<br><br><br>procedure TADTrayIcon.SetIconList(Value: TImageList);<br>begin<br>&nbsp; FIconList := Value;<br>{<br>&nbsp; // Set CycleIcons = false if IconList is nil<br>&nbsp; if Value = nil then<br>&nbsp; &nbsp; SetCycleIcons(False);<br>}<br>&nbsp; SetIconIndex(0);<br>end;<br><br><br>procedure TADTrayIcon.SetIconIndex(Value: Integer);<br>begin<br>&nbsp; if FIconList &lt;&gt; nil then<br>&nbsp; begin<br>&nbsp; &nbsp; FIconIndex := Value;<br>&nbsp; &nbsp; if Value &gt;= FIconList.Count then<br>&nbsp; &nbsp; &nbsp; FIconIndex := FIconList.Count -1;<br>&nbsp; &nbsp; FIconList.GetIcon(FIconIndex, FIcon);<br>&nbsp; end<br>&nbsp; else<br>&nbsp; &nbsp; FIconIndex := 0;<br><br>&nbsp; ModifyIcon;<br>end;<br><br><br>procedure TADTrayIcon.SetHint(Value: String);<br>begin<br>&nbsp; FHint := Value;<br>&nbsp; ModifyIcon;<br>end;<br><br><br>function TADTrayIcon.InitIcon: Boolean;<br>// Set icon and tooltip<br>var<br>&nbsp; ok: Boolean;<br>begin<br>&nbsp; Result := False;<br>&nbsp; ok := True;<br>&nbsp; if (csDesigning in ComponentState) and SettingPreview then<br>&nbsp; &nbsp; ok := FDesignPreview;<br><br>&nbsp; if ok then<br>&nbsp; begin<br>&nbsp; &nbsp; IconData.hIcon := FIcon.Handle;<br>&nbsp; &nbsp; if FHint &lt;&gt; '' then<br>&nbsp; &nbsp; &nbsp; StrLCopy(IconData.szTip, PChar(FHint), SizeOf(IconData.szTip)-1)<br>&nbsp; &nbsp; &nbsp; // StrLCopy must be used since szTip is only 64 bytes<br>&nbsp; &nbsp; else<br>&nbsp; &nbsp; &nbsp; IconData.szTip := '';<br>&nbsp; &nbsp; Result := True;<br>&nbsp; end;<br>end;<br><br><br>function TADTrayIcon.ShowIcon: Boolean;<br>// Add/show the icon on the tray<br>begin<br>&nbsp; Result := False;<br>&nbsp; if not SettingPreview then<br>&nbsp; &nbsp; FIconVisible := True;<br>&nbsp; begin<br>&nbsp; &nbsp; if (csDesigning in ComponentState) {or<br>&nbsp; &nbsp; &nbsp;(csLoading in ComponentState)} then<br>&nbsp; &nbsp; begin<br>&nbsp; &nbsp; &nbsp; if SettingPreview then<br>&nbsp; &nbsp; &nbsp; &nbsp; if InitIcon then<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Result := Shell_NotifyIcon(NIM_ADD, @IconData);<br>&nbsp; &nbsp; end<br>&nbsp; &nbsp; else<br>&nbsp; &nbsp; if InitIcon then<br>&nbsp; &nbsp; &nbsp; Result := Shell_NotifyIcon(NIM_ADD, @IconData);<br>&nbsp; end;<br>end;<br><br><br>function TADTrayIcon.HideIcon: Boolean;<br>// Remove/hide the icon from the tray<br>begin<br>&nbsp; Result := False;<br>&nbsp; if not SettingPreview then<br>&nbsp; &nbsp; FIconVisible := False;<br>&nbsp; begin<br>&nbsp; &nbsp; if (csDesigning in ComponentState) {or<br>&nbsp; &nbsp; &nbsp;(csLoading in ComponentState)} then<br>&nbsp; &nbsp; begin<br>&nbsp; &nbsp; &nbsp; if SettingPreview then<br>&nbsp; &nbsp; &nbsp; &nbsp; if InitIcon then<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Result := Shell_NotifyIcon(NIM_DELETE, @IconData);<br>&nbsp; &nbsp; end<br>&nbsp; &nbsp; else<br>&nbsp; &nbsp; if InitIcon then<br>&nbsp; &nbsp; &nbsp; Result := Shell_NotifyIcon(NIM_DELETE, @IconData);<br>&nbsp; end;<br>end;<br><br><br>function TADTrayIcon.ModifyIcon: Boolean;<br>// Change icon or tooltip if icon already placed<br>begin<br>&nbsp; Result := False;<br>&nbsp; if InitIcon then<br>&nbsp; &nbsp; Result := Shell_NotifyIcon(NIM_MODIFY, @IconData);<br>end;<br><br><br>procedure TADTrayIcon.TimerCycle(Sender: TObject);<br>begin<br>&nbsp; if Assigned(FIconList) then<br>&nbsp; begin<br>&nbsp; &nbsp; FIconList.GetIcon(FIconIndex, FIcon);<br>&nbsp; &nbsp; CycleIcon; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;// Call event method<br>&nbsp; &nbsp; ModifyIcon;<br><br>&nbsp; &nbsp; if FIconIndex &lt; FIconList.Count-1 then<br>&nbsp; &nbsp; &nbsp; SetIconIndex(FIconIndex+1)<br>&nbsp; &nbsp; else<br>&nbsp; &nbsp; &nbsp; SetIconIndex(0);<br>&nbsp; end;<br>end;<br><br><br>function TADTrayIcon.ShowBalloonHint(Title: String; Text: String;<br>&nbsp; IconType: TBalloonHintIcon; TimeoutSecs: TBalloonHintTimeOut): Boolean;<br>const<br>&nbsp; aBalloonIconTypes: array[TBalloonHintIcon] of Byte = (NIIF_NONE, NIIF_INFO, NIIF_WARNING, NIIF_ERROR);<br>begin<br>&nbsp; if FEnabled then<br>&nbsp; begin<br>&nbsp; &nbsp; // Remove old balloon hint<br>&nbsp; &nbsp; with IconData do<br>&nbsp; &nbsp; begin<br>&nbsp; &nbsp; &nbsp; uFlags := uFlags or NIF_INFO;<br>&nbsp; &nbsp; &nbsp; StrPCopy(szInfo, '');<br>&nbsp; &nbsp; end;<br>&nbsp; &nbsp; ModifyIcon;<br>&nbsp; &nbsp; // Display new balloon hint<br>&nbsp; &nbsp; with IconData do<br>&nbsp; &nbsp; begin<br>&nbsp; &nbsp; &nbsp; uFlags := uFlags or NIF_INFO;<br>&nbsp; &nbsp; &nbsp; StrPCopy(szInfo, Text);<br>&nbsp; &nbsp; &nbsp; StrPCopy(szInfoTitle, Title);<br>&nbsp; &nbsp; &nbsp; uTimeout := TimeoutSecs * 1000;<br>&nbsp; &nbsp; &nbsp; dwInfoFlags := aBalloonIconTypes[IconType];<br>&nbsp; &nbsp; end;<br>&nbsp; &nbsp; Result := ModifyIcon;<br>&nbsp; &nbsp; { Remove NIF_INFO before next call to ModifyIcon (or else the balloon hint<br>&nbsp; &nbsp; &nbsp; will redisplay itself) }<br>&nbsp; &nbsp; with IconData do<br>&nbsp; &nbsp; &nbsp; uFlags := NIF_ICON + NIF_MESSAGE + NIF_TIP;<br>&nbsp; end<br>&nbsp; else<br>&nbsp; &nbsp; Result := True;<br>end;<br><br><br>procedure TADTrayIcon.Refresh;<br>// Refresh the icon<br>begin<br>&nbsp; ModifyIcon;<br>end;<br><br><br>procedure TADTrayIcon.PopupAtCursor;<br>var<br>&nbsp; CursorPos: TPoint;<br>begin<br>&nbsp; if Assigned(PopupMenu) then<br>&nbsp; &nbsp; if PopupMenu.AutoPopup then<br>&nbsp; &nbsp; &nbsp; if GetCursorPos(CursorPos) then<br>&nbsp; &nbsp; &nbsp; begin<br>&nbsp; &nbsp; &nbsp; &nbsp; { Win98 (but not Win95/WinNT) seems to empty a popup menu before<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; closing it. This is a problem when the menu is about to display<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; while it already is active (two click-events in succession). The<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; menu will flicker annoyingly. Calling ProcessMessages fixes this. }<br>&nbsp; &nbsp; &nbsp; &nbsp; Application.ProcessMessages;<br><br>&nbsp; &nbsp; &nbsp; &nbsp; { Bring the main form or its modal dialog to the foreground.<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; This also ensures the popup menu closes after it loses focus. }<br>&nbsp; &nbsp; &nbsp; &nbsp; SetForegroundWindow((Owner as TWinControl).Handle);<br>{<br>This seems unnecessary(?):<br>&nbsp; &nbsp; &nbsp; &nbsp; if Screen.ActiveControl &lt;&gt; nil then<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (Screen.ActiveControl.Owner is TWinControl) then<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; SetForegroundWindow((Screen.ActiveControl.Owner as TWinControl).Handle);<br>}<br>&nbsp; &nbsp; &nbsp; &nbsp; // Now make the menu pop up<br>&nbsp; &nbsp; &nbsp; &nbsp; PopupMenu.PopupComponent := Self;<br>&nbsp; &nbsp; &nbsp; &nbsp; PopupMenu.Popup(CursorPos.X, CursorPos.Y);<br>&nbsp; &nbsp; &nbsp; &nbsp; // Post an empty message to make the popup menu disappear<br>&nbsp; &nbsp; &nbsp; &nbsp; PostMessage((Owner as TWinControl).Handle, WM_NULL, 0, 0);<br>&nbsp; &nbsp; &nbsp; end;<br>end;<br><br><br>procedure TADTrayIcon.Click;<br>begin<br>&nbsp; // Execute user-assigned method<br>&nbsp; if Assigned(FOnClick) then<br>&nbsp; &nbsp; FOnClick(Self);<br>end;<br><br><br>procedure TADTrayIcon.DblClick;<br>begin<br>&nbsp; // Execute user-assigned method<br>&nbsp; if Assigned(FOnDblClick) then<br>&nbsp; &nbsp; FOnDblClick(Self);<br>end;<br><br><br>procedure TADTrayIcon.MouseDown(Button: TMouseButton; Shift: TShiftState;<br>&nbsp; X, Y: Integer);<br>begin<br>&nbsp; // Execute user-assigned method<br>&nbsp; if Assigned(FOnMouseDown) then<br>&nbsp; &nbsp; FOnMouseDown(Self, Button, Shift, X, Y);<br>end;<br><br><br>procedure TADTrayIcon.MouseUp(Button: TMouseButton; Shift: TShiftState;<br>&nbsp; X, Y: Integer);<br>begin<br>&nbsp; // Execute user-assigned method<br>&nbsp; if Assigned(FOnMouseUp) then<br>&nbsp; &nbsp; FOnMouseUp(Self, Button, Shift, X, Y);<br>end;<br><br><br>procedure TADTrayIcon.MouseMove(Shift: TShiftState; X, Y: Integer);<br>begin<br>&nbsp; // Execute user-assigned method<br>&nbsp; if Assigned(FOnMouseMove) then<br>&nbsp; &nbsp; FOnMouseMove(Self, Shift, X, Y);<br>end;<br><br><br>procedure TADTrayIcon.CycleIcon;<br>var<br>&nbsp; NextIconIndex: Integer;<br>begin<br>&nbsp; // Execute user-assigned method<br>&nbsp; NextIconIndex := 0;<br>&nbsp; if FIconList &lt;&gt; nil then<br>&nbsp; &nbsp; if FIconIndex &lt; FIconList.Count then<br>&nbsp; &nbsp; &nbsp; NextIconIndex := FIconIndex +1;<br><br>&nbsp; if Assigned(FOnCycle) then<br>&nbsp; &nbsp; FOnCycle(Self, NextIconIndex);<br>end;<br><br><br>procedure Register;<br>begin<br>&nbsp; RegisterComponents('Adnil Studio', [TADTrayIcon]);<br>end;<br><br>end.<br>
 
PRB: Menus for Notification Icons Do Not Work Correctly <br><br>--------------------------------------------------------------------------------<br>The information in this article applies to:<br><br>Microsoft Win32 Software Development Kit (SDK)<br><br>--------------------------------------------------------------------------------<br><br><br>SYMPTOMS<br>When you display a context menu for a notification icon (see Shell_NotifyIcon), clicking anywhere besides the menu or the window that created the menu (if it is visible) doesn't cause the menu to disappear. When this behavior is corrected, the second time this menu is displayed, it displays and then immediately disappears. <br><br><br><br>RESOLUTION<br>To correct the first behavior, you need to make the current window the foreground window before calling TrackPopupMenu or TrackPopupMenuEx. <br><br>The second problem is caused by a problem with TrackPopupMenu. It is necessary to force a task switch to the application that called TrackPopupMenu at some time in the near future. This can be accomplished by posting a benign message to the window or thread. <br><br>The following code will take care of all of this: <br><br><br>&nbsp; &nbsp;[red]SetForegroundWindow(hDlg);[/red]<br><br>&nbsp; &nbsp;// Display the menu<br>&nbsp; &nbsp;TrackPopupMenu( &nbsp; hSubMenu,<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;TPM_RIGHTBUTTON,<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;pt.x,<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;pt.y,<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;0,<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;hDlg,<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;NULL);<br><br>&nbsp; &nbsp;PostMessage(hDlg, WM_NULL, 0, 0); <br><br><br><br>STATUS<br>This behavior is by design. <br><br>Additional query words: <br><br>Keywords : kbcode kbLib kbMenu kbNTOS400 kbWinOS95 kbWinOS98 kbshell <br>Version : WINDOWS: <br>Platform : WINDOWS <br>Issue type : kbprb <br>Technology : <br><br><br>Last Reviewed: January 6, 2000<br>&amp;copy; 2000 Microsoft Corporation. All rights reserved. Terms of Use.<br>&nbsp;<br><br><br><br>--------------------------------------------------------------------------------<br>Send feedback to MSDN.Look here for MSDN Online resources.
 
多人接受答案了。
 
后退
顶部