2015-04-07 88 views
4

所以我一直在基於兩個不同的源代碼工作在這個TrayIcon組件上。彈出菜單顯示在FMX的任務欄後面Delphi

一個用於Windows,一個用於Mac。

一切正常,除了當使用FMX TPopupMenu作爲托盤圖標菜單時,它會一直彈出到任務欄後面,有時在托盤圖標容器中右擊應用程序圖標時它甚至不會彈出知道包含所有隱藏圖標的小盒子?)

I found an article on the internet (read here)其中提示VCL TPopupMenu將是一種解決方法。

我的應用程序是跨平臺的,我使用FMX,所以我需要使用FMX組件。

現在對於這個問題:我該如何在任務欄前彈出一個FMX菜單?

編輯: 注1:我使用Delphi XE7在Windows 8.1 注2:在所附的代碼,有uses子句中的一部分,可以測試任何FMX.Menus或VCL進行註釋.Menus,然後 在構造函數Create中有一段代碼也必須取消註釋,以便與VCL.Menus一起使用。

這裏是我的托盤圖標代碼:

{The source is from Nix0N, [email protected], www.nixcode.ru, Ver 0.1. 
} 

unit QTray; 

interface 

uses 
    System.SysUtils, System.Classes, System.TypInfo, 
    System.UITypes, 

    Winapi.ShellAPI, Winapi.Windows, 
    Winapi.Messages, FMX.Platform.Win, VCL.graphics, 
    VCL.Controls, 

    FMX.Dialogs, FMX.Forms, 
    FMX.Objects, FMX.Types, 
    FMX.Graphics, FMX.Surfaces, 
    FMX.Menus //Comment this to use FMX Menus 
// , VCL.Menus //comment this to use VCL Menus 
    ; 

type 
    TOnBalloonClick = procedure(Sender: TObject; ID: integer; ATagStr: string) of object; 
    TBalloonIconType = (None, Info, Warning, Error, User, BigWarning, BigError); 




    TCrossTray = class 
    private 
    fForm : TForm; 
    fHint : string; 
    fBalloonTitle  : string; 
    fBalloonText  : string; 
    fBalloonIconType : TBalloonIconType; 
    fTrayIcon  : TNotifyIconData ; 
    fTrayMenu  : TPopupMenu  ; 
    fIndent  : Integer   ; 

    fOnClick  : TNotifyEvent ; 
    fOnMouseDown, 
    fOnMouseUp, 
    fOnDblClick : TMouseEvent  ; 
    fOnMouseEnter, 
    fOnMouseLeave : TNotifyEvent ; 
// fOnMouseMove : TMouseMoveEvent ; 

    fOnBalloonShow, 
    fOnBalloonHide, 
    fOnBalloonTimeout : TNotifyEvent ; 
    fOnBalloonUserClick : TOnBalloonClick ; 

    fWinIcon : TIcon; 



    procedure ShowBallonHint; 
    protected 
    public 
    constructor Create; overload; 
    constructor Create(AForm: TForm); overload;//AForm isn't used in MacOS, but is left there for seamless inegration in your app 
    destructor Destroy; 

    procedure CreateMSWindows; 
    procedure Show; 
    procedure Hide; 

    procedure Balloon   (ATitle, AMessage: string; AType: TBalloonIconType; AID: integer; ATagStr: string); 
    procedure BalloonNone  (ATitle, AMessage: string; AID: integer; ATagStr: string); 
    procedure BalloonInfo  (ATitle, AMessage: string; AID: integer; ATagStr: string); 
    procedure BalloonWarning (ATitle, AMessage: string; AID: integer; ATagStr: string); 
    procedure BalloonWarningBig (ATitle, AMessage: string; AID: integer; ATagStr: string); 
    procedure BalloonError  (ATitle, AMessage: string; AID: integer; ATagStr: string); 
    procedure BalloonErrorBig (ATitle, AMessage: string; AID: integer; ATagStr: string); 
    procedure BalloonUser  (ATitle, AMessage: string; AID: integer; ATagStr: string); 





    procedure LoadIconFromFile(APath: UTF8String); 
    procedure OnIconChange(Sender: TObject); 

    function GetIconRect: TRect; 
    published 

    property Hint    : string   read fHint    write fHint    ; 
    property BalloonText  : string   read fBalloonText   write fBalloonText  ; 
    property BalloonTitle  : string   read fBalloonTitle  write fBalloonTitle  ; 
    property IconBalloonType : TBalloonIconType read fBalloonIconType  write fBalloonIconType ; 
    property Indent    : Integer   read fIndent    write fIndent    ; 
    property PopUpMenu   : TPopupMenu  read fTrayMenu   write fTrayMenu   ; 


    property OnClick   : TNotifyEvent  read fOnClick    write fOnClick   ; 
    property OnMouseDown  : TMouseEvent  read fOnMouseDown   write fOnMouseDown  ; 
    property OnMouseUp   : TMouseEvent  read fOnMouseUp   write fOnMouseUp   ; 
    property OnDblClick   : TMouseEvent  read fOnDblClick   write fOnDblClick   ; 

    property OnMouseEnter  : TNotifyEvent  read fOnMouseEnter  write fOnMouseEnter  ; 
    property OnMouseLeave  : TNotifyEvent  read fOnMouseLeave  write fOnMouseLeave  ; 


    property OnBalloonShow  : TNotifyEvent  read fOnBalloonShow  write fOnBalloonShow  ; 
    property OnBalloonHide  : TNotifyEvent  read fOnBalloonHide  write fOnBalloonHide  ; 
    property OnBalloonTimeout : TNotifyEvent  read fOnBalloonTimeout write fOnBalloonTimeout ; 
    property OnBalloonUserClick : TOnBalloonClick read fOnBalloonUserClick write fOnBalloonUserClick ; 

// property OnMouseMove  : TMouseMoveEvent read fOnMouseMove  write fOnMouseMove  ; 

    end; 


    var 
    gOldWndProc: LONG_PTR; 
    gHWND: TWinWindowHandle; 
    gPopUpMenu: TPopupMenu; 
    gFirstRun: Boolean = True; 
    gIndent: Integer; 

    gOnClick  : TNotifyEvent ; 
    gOnMouseDown, 
    gOnMouseUp, 
    gOnDblClick : TMouseEvent  ; 
    gOnMouseEnter, 
    gOnMouseLeave : TNotifyEvent; 
// gOnMouseMove : TMouseMoveEvent ; 

    gOnBalloonShow, 
    gOnBalloonHide, 
    gOnBalloonTimeout : TNotifyEvent ; 
    gOnBalloonUserClick : TOnBalloonClick ; 

    gBalloonID: integer; 
    gBalloonTagStr: string; 

    gXTrayIcon: TCrossTray; 

    function MyWndProc(HWND: HWND; Msg: UINT; WParam: WParam; LParam: LParam): LRESULT; stdcall; 

    const WM_TRAYICON = WM_USER + 1; 



implementation 

constructor TCrossTray.Create; 
begin 


end; 

constructor TCrossTray.Create(AForm: TForm); 
begin 
    inherited Create; 

    fForm := AForm; CreateMSWindows; 


    //uncomment the following block for a simple hello world menu using VCL.Menu 
    { fTrayMenu := TPopupMenu.Create(nil); 
    fTrayMenu.Items.Add(TMenuItem.Create(nil)); 
    fTrayMenu.Items.Add(TMenuItem.Create(nil)); 
    fTrayMenu.Items.Items[0].Caption := 'hello'; 
    fTrayMenu.Items.Items[1].Caption := 'world!'; 
    } 

    //To use FMX Menus, just assign one from your main form 

end; 



procedure TCrossTray.CreateMSWindows; 
begin 
    fWinIcon := TIcon.Create; 
    fWinIcon.OnChange := OnIconChange; 

    fIndent := 75; 

    Show; 
end; 

function MyWndProc(HWND: HWND; Msg: UINT; WParam: WParam; LParam: LParam): LRESULT; stdcall; 
var 
    CurPos: TPoint; 
    Shift: TShiftState; 
begin 
    Result := 0; 

    GetCursorPos(CurPos); 

    Shift := []; 

    if Msg = WM_TRAYICON then 
    begin 
    case lParam of 
     NIN_BALLOONSHOW  : if assigned(gOnBalloonShow) then gOnBalloonShow(nil)  ; //when balloon has been showed 
     NIN_BALLOONHIDE  : if assigned(gOnBalloonHide) then gOnBalloonHide(nil)  ; //when balloon has been hidden 
     NIN_BALLOONTIMEOUT : if assigned(gOnBalloonTimeout) then gOnBalloonTimeout(nil) ; //when balloon has been timed out 
     NIN_BALLOONUSERCLICK : if assigned(gOnBalloonUserClick) then gOnBalloonUserClick(nil, gBalloonID, gBalloonTagStr) ; //when balloon has been clicked 

     WM_LBUTTONDOWN  : if assigned(gOnMouseDown) then gOnMouseDown(nil, mbLeft, Shift, CurPos.X, CurPos.Y); //when LEFT mouse button is DOWN on the tray icon 
     WM_RBUTTONDOWN  : if assigned(gOnMouseDown) then gOnMouseDown(nil, mbRight, Shift, CurPos.X, CurPos.Y); //when RIGHT mouse button is DOWN on the tray icon 

     WM_LBUTTONUP   : //when LEFT mouse button is UP on the tray icon 
     begin 
      if assigned(gOnMouseUp) then gOnMouseUp(nil, mbLeft, Shift, CurPos.X, CurPos.Y); 
      if assigned(gOnClick) then gOnClick(nil); 
     end; 

     WM_RBUTTONUP   : //when RIGHT mouse button is UP on the tray icon 
     begin 
      if assigned(gOnMouseUp) then gOnMouseUp(nil, mbRight, Shift, CurPos.X, CurPos.Y); 

      SetForegroundWindow(gHWND.Wnd); 
      if assigned(gPopUpMenu) then gPopUpMenu.PopUp(CurPos.X, CurPos.Y - gIndent); 
     end; 

     WM_LBUTTONDBLCLK  : if assigned(gOnDblClick) then gOnDblClick(nil, mbLeft, Shift, CurPos.X, CurPos.Y); //when tray icon has been DOUBLECLICKED with LEFT mouse button 
     WM_RBUTTONDBLCLK  : if assigned(gOnDblClick) then gOnDblClick(nil, mbRight, Shift, CurPos.X, CurPos.Y); //when tray icon has been DOUBLECLICKED with RIGHT mouse button 

     WM_MOUSEHOVER : if assigned(gOnMouseEnter) then gOnMouseEnter(nil); 
     WM_MOUSELEAVE : showmessage('a');//if assigned(gOnMouseLeave) then gOnMouseLeave(nil); 

//  WM_MOUSEMOVE   : gOnMouseMove(nil, Shift, CurPos.X, CurPos.Y); //This one causes an error 
    end; 
    end; 

    Result := CallWindowProc(Ptr(gOldWndProc), HWND, Msg, WParam, LParam); 
end; 

procedure TCrossTray.Show; 
begin 
    gHWND   := WindowHandleToPlatform(fForm.Handle); 
    gPopUpMenu := fTrayMenu ; 
    gIndent  := fIndent  ; 

    gOnClick   := fOnClick    ; 
    gOnMouseDown  := fOnMouseDown   ; 
    gOnMouseUp   := fOnMouseUp   ; 
    gOnDblClick   := fOnDblClick   ; 
    gOnMouseEnter  := fOnMouseEnter  ; 
    gOnMouseLeave  := fOnMouseLeave  ; 
// gOnMouseMove  := fOnMouseMove   ; 
    gOnBalloonShow  := fOnBalloonShow  ; 
    gOnBalloonHide  := fOnBalloonHide  ; 
    gOnBalloonTimeout := fOnBalloonTimeout ; 
    gOnBalloonUserClick := fOnBalloonUserClick ; 

    with fTrayIcon do 
    begin 
    cbSize := SizeOf; 
    Wnd := gHWND.Wnd; 
    uID := 1; 
    uFlags := NIF_MESSAGE + NIF_ICON + NIF_TIP;// + NIF_STATE + NIF_INFO + NIF_GUID + NIF_REALTIME + NIF_SHOWTIP; 
    dwInfoFlags := NIIF_NONE; 
    uCallbackMessage := WM_TRAYICON; 
    hIcon := GetClassLong(gHWND.Wnd, GCL_HICONSM); 
    StrLCopy(szTip, PChar(fHint), High(szTip)); 
    end; 

    Shell_NotifyIcon(NIM_ADD, @fTrayIcon); 

    if gFirstRun then 
    begin 
    gOldWndProc := GetWindowLongPtr(gHWND.Wnd, GWL_WNDPROC); 
    SetWindowLongPtr(gHWND.Wnd, GWL_WNDPROC, LONG_PTR(@MyWndProc)); 
    gFirstRun := False; 
    end; 
end; 

procedure TCrossTray.ShowBallonHint; 
begin 
    with fTrayIcon do 
    begin 
    StrLCopy(szInfo, PChar(fBalloonText), High(szInfo)); 
    StrLCopy(szInfoTitle, PChar(fBalloonTitle), High(szInfoTitle)); 
    uFlags := NIF_INFO; 

    case fBalloonIconType of 
     None  : dwInfoFlags := 0; 
     Info  : dwInfoFlags := 1; 
     Warning  : dwInfoFlags := 2; 
     Error  : dwInfoFlags := 3; 
     User  : dwInfoFlags := 4; 
     BigWarning : dwInfoFlags := 5; 
     BigError : dwInfoFlags := 6; 
    end; 
    end; 

    Shell_NotifyIcon(NIM_MODIFY, @fTrayIcon); 
end; 

procedure TCrossTray.Balloon(ATitle, AMessage: string; AType: TBalloonIconType; AID: integer; ATagStr: string); 
begin 
    BalloonTitle := ATitle ; 
    BalloonText  := AMessage ; 
    IconBalloonType := AType ; 
    gBalloonID  := AID  ; 
    gBalloonTagStr := ATagStr ; 
    ShowBallonHint; 
end; 

procedure TCrossTray.BalloonNone(ATitle, AMessage: string; AID: integer; ATagStr: string); 
begin 
    Balloon(ATitle, AMessage, None, AID, ATagStr); 
end; 

procedure TCrossTray.BalloonInfo(ATitle, AMessage: string; AID: integer; ATagStr: string); 
begin 
    Balloon(ATitle, AMessage, Info, AID, ATagStr); 
end; 

procedure TCrossTray.BalloonWarning(ATitle, AMessage: string; AID: integer; ATagStr: string); 
begin 
    Balloon(ATitle, AMessage, Warning, AID, ATagStr); 
end; 

procedure TCrossTray.BalloonWarningBig(ATitle, AMessage: string; AID: integer; ATagStr: string); 
begin 
    Balloon(ATitle, AMessage, BigWarning, AID, ATagStr); 
end; 

procedure TCrossTray.BalloonError(ATitle, AMessage: string; AID: integer; ATagStr: string); 
begin 
    Balloon(ATitle, AMessage, Error, AID, ATagStr); 
end; 

procedure TCrossTray.BalloonErrorBig(ATitle, AMessage: string; AID: integer; ATagStr: string); 
begin 
    Balloon(ATitle, AMessage, BigError, AID, ATagStr); 
end; 

procedure TCrossTray.BalloonUser(ATitle, AMessage: string; AID: integer; ATagStr: string); 
begin 
    Balloon(ATitle, AMessage, User, AID, ATagStr); 
end; 



procedure TCrossTray.Hide; 
begin 
    Shell_NotifyIcon(NIM_DELETE, @fTrayIcon); 
end; 

destructor TCrossTray.Destroy; 
begin 
    Shell_NotifyIcon(NIM_DELETE, @fTrayIcon); 
    fWinIcon.Free; 
    inherited; 
end; 

procedure TCrossTray.OnIconChange(Sender: TObject); 
begin 
    fTrayIcon.hIcon := fWinIcon.Handle; 
    Shell_NotifyIcon(NIM_MODIFY, @fTrayIcon); 
end; 

function TCrossTray.GetIconRect: TRect; 
    var S: NOTIFYICONIDENTIFIER; 
begin 
    FillChar(S, SizeOf(S), #0); 
    S.cbSize := SizeOf(NOTIFYICONIDENTIFIER); 
    S.hWnd := fTrayIcon.Wnd; 
    S.uID := fTrayIcon.uID; 

    Shell_NotifyIconGetRect(S, result); 
end; 




procedure TCrossTray.LoadIconFromFile(APath: UTF8String); 
begin 
    fWinIcon.LoadFromFile(APath); 
end; 

end. 
+1

這是一個代碼牆。例如,我們打算如何處理mac代碼。你不能爲我們削減它嗎? –

+0

@DavidHeffernan你是對的,在這種情況下mac代碼不是必需的,因爲它是完全功能的。我更新了代碼塊。 – vaid

回答

0

替換:

gHWND   := WindowHandleToPlatform(fForm.Handle); 

有了:

gHWND   := ApplicationHWND; 
+0

gHWND:= WindowHandleToPlatform(ApplicationHWND); –

+0

您是否找到解決方案?我也有同樣的問題 :( – loki