Windows 95 和 Windows NT 4.0包含一個令人興奮的特性:任務欄。這個通常位于區域任務條右面的區域能包含小的圖標,這些圖標能引出大的應用程序或者菜單。本篇文章主要討論如何使用Delphi建立這樣的應用程序。 在開始之前,請看下面的需要的接口方面的內容: 從技術方面來說,一個任務欄應用程序非常象普通的應用程序,它有一個消息循環,相應Windows的消息來完成相應的功能。
Procedure RunTrayApplication; Var Msg : TMsg; Begin CreateWindow; AddTrayIcon; While GetMessage(Msg,0,0,0) do Begin TranslateMessage(Msg); DispatchMessage(Msg); End; DeleteTrayIcon; End; 你能看到:所有需要做的工作是創建一個窗口,注冊一個圖標到任務欄,設置它的消息循環,最后關閉它。當然,必須還有增加其他代碼完成相應的功能,但是,它是真的不需要擔心。 讓我們從窗口的創建開始。實際上,這個窗口是不是能在任務欄上能見到的窗口。相應的,這個窗口只是處理消息循環、其它父類的工作。任務窗口(Windows 95 & NT)句柄創建消息(例如鼠標單擊等)和將消息發到我們的窗口。
Procedure CreateWindow; Var WC : TWndClass; W : hWnd; Begin With WC do Begin Style := 0; lpfnWndProc := @WndProc; cbClsExtra := 0; cbWndExtra := 0; hIcon := 0; hCursor := 0; hbrBackground := 0; lpszMenuName := nil; lpszClassName := 'MyTrayIconClass'; hInstance := System.hInstance; end; RegisterClass(WC); W := Windows.CreateWindow('MyTrayIconClass','MyVeryOwnTrayIconWindow', ws_OverlappedWindow,0,0,0,0,0,0,hInstance,nil); ShowWindow(W,sw_Hide); UpdateWindow(W); MainWindow := W; End; 這個窗口使用普通的窗口函數創建。注意這個窗口的類型是“ws_OverlappedWindow”,但是這個尺寸是0,并且它是隱藏的,所有,它將不會顯示出來。 下一步是加(注冊)我們的圖標。這將需要使用Shell_NotifyIcon這個API函數,這個函數實際上可以完成三個功能,這里只需要它的增加的特性。
Procedure AddTrayIcon; Var IconData : TNotifyIconData; Begin With IconData do Begin cbSize := SizeOf(IconData); Wnd := MainWindow; uID := 0; uFlags := nif_Icon Or nif_Message Or nif_Tip; uCallBackMessage := wm_MyCallBack; hIcon := LoadIcon(hInstance,'MYICON'); StrCopy(szTip,PChar(TrayIconTip)); End; Shell_NotifyIcon(nim_Add,@IconData); End; 這個最重要的事情是TNotifyIconData的數據結構,它是一個設置Window句柄的數據結構,是一個記錄參數,對我們來說,我們需要設置這個圖標的窗口句柄(這將定義哪個窗口處理消息循環),回調消息號,圖標,工具提示等。一旦這個數據設置了,我們就可以增加一個圖標到任務欄上了。為了完成這個工作,使用nim_Add程序。 現行我們已經加了我們的圖標到任務欄,下面需要決定如何處理消息。
Const wm_MyCallback = wm_User+1000; cm_Exit = 100; { we worry about... } cm_About = 101; { ...these later } 這個實際的窗口處理過程也是相當普通。幾個窗口消息(如wm_NCCreate)必須處理。然而,對我們來說,更重要的事情是處理wm_MyCallback和wm_Command消息: Function WndProc(Window : hWnd; Msg,WParam,LParam : Integer): Integer; StdCall; Begin Result := 0; Case Msg of wm_NCCreate : Result := 1; wm_Destroy : PostQuitMessage(0); wm_Command : Begin { a command was chosen from the popup menu } If (WParam = cm_Exit) Then PostMessage(Window,wm_Destroy,0,0) Else If (WParam = cm_About) Then MessageBox(0,'Shell Test Copyright ?'+ 'Jani J鋜vinen 1996.', 'About Shell Test',mb_OK) Else OpenDesktopIcon(WParam-cm_About); End; wm_MyCallback : Begin { our icon was clicked } If (LParam = wm_LButtonDown) Then ShowIconPopupMenu Else If (LParam = wm_RButtonDown) Then ShowAboutPopupMenu; End; Else Result := DefWindowProc(Window,Msg,WParam,LParam); End; End; 就象你看到的一樣,當用戶單擊圖標時,Windows提示我們。注意我們不使用通常使用的wm_LButtonDown 消息,而使用wm_MyCallback message,詳細的消息信息存儲在LParam參數中。 當用戶單擊鼠標右鍵,我們創建一個菜單在桌面上。
Type TIconData = Array[1..100] of String; Var IconData : TIconData; Procedure ShowIconPopupMenu; Var ShellFolder : IShellFolder; EnumIDList : IEnumIDList; Result : hResult; Dummy : ULong; ItemIDList : TItemIDList; Pntr : PItemIDList; StrRet : TStrRet; PopupMenu : hMenu; ItemID : Integer; Pos : TPoint; Procedure AddToMenu(Item : String); Var S : String; Begin IconData[ItemID-cm_About] := Item; S := ExtractFileName(Item); If (System.Pos('.',S) <> 0) Then SetLength(S,System.Pos('.',S)-1); AppendMenu(PopupMenu,mf_Enabled Or mf_String,ItemID,PChar(S)); Inc(ItemID); End; begin PopupMenu := CreatePopupMenu; ItemID := cm_About+1; SHGetDesktopFolder(ShellFolder); ShellFolder.EnumObjects(MainWindow,SHCONTF_NONFOLDERS,EnumIDList); Pntr := @ItemIDList; Result := EnumIDList.Next(1,Pntr,Dummy); While (Result = NoError) do Begin ShellFolder.GetDisplayNameOf(Pntr,SHGDN_FORPARSING,@StrRet); With StrRet do AddToMenu(String(CStr)); Result := EnumIDList.Next(1,Pntr,Dummy); End; EnumIDList.Release; ShellFolder.Release; GetCursorPos(Pos); AppendMenu(PopupMenu,mf_Separator,0,''); AppendMenu(PopupMenu,mf_Enabled Or mf_String,cm_Exit,'E&xit'); SetForegroundWindow(MainWindow); TrackPopupMenu(PopupMenu,tpm_LeftAlign Or tpm_LeftButton, Pos.X,Pos.Y,0,MainWindow,nil); DestroyMenu(PopupMenu); end; 上面的程序看起來有點復雜,你可以將它分成兩個部分來看:創建和顯示菜單。 列舉創建菜單是用Windows的外殼接口完成的。首先,我們使用SHGetDesktopForlder函數得到使用桌面的IShellFolder接口。使用這個接口,我們能得到另一個接口的實例:IEnumIDList。這個接口通常實現實際的列舉工作。我們簡單的重復調用這個函數直到錯誤值返回(例如:所有的菜單被列舉)。當我們得到一個菜單,我們使用AddToMenu函數加它。
當所有的菜單被列舉和創建后,現在我們需要運行這個菜單。我們將找到的菜單保存到一個全局的List變量中,每一個菜單都擁有它的菜單號。這確保我們能得到它的索引。
OpenDesktopIcon(WParam-cm_About)
當然,WParam中儲存了用戶單擊鼠標的菜單的菜單號(ID)。
下面我們將處理運行用戶選擇的菜單。
Procedure OpenDesktopIcon(Number : Integer); Var S : String; I : Integer; begin S := IconData[Number]; I := ShellExecute(0,nil,PChar(S),nil,nil,sw_ShowNormal); If (I < 32) Then Begin S := 'Could not open selected item "'+S+'". '+ 'Result was: '+IntToStr(I)+'.'; MessageBox(0,PChar(S),'Shell Test',mb_OK); End; end; 上面,Win 32 API函數ShellExecute做了所有的工作。
現在你應該能用Delphi創建簡單的任務欄的程序了。
實際上,有一些免費的元件可以供您直接使用,不過,因為使用VCL,文件的大小將比較大,如果使用上面的方法,文件的大小將只要20K。當然,現在文件的大小已經不是我們該十分關注的問題了。
|