本帖最后由 群发软件 于 2017-8-8 21:23 编辑
使用Windows95/NT/98操作系统的用户知道:Windows正常启动后,在电脑屏幕下方出现一块 任务栏。从系统功能角度而言,整个任务栏包括几个不同的子区域,从左至右依次是:开始 按钮、应用程序切换区(Application Switch Bar)、任务栏通知区(Notification Area)以 及任务栏时钟。与其它Windows应用程序相同,任务栏程序(systray.exe)由几个不同的窗体 组成,这些窗体是具有各自的窗口类名、显示方式等信息。因此,只要得到有关窗口信息, 即可通过编程全面控制Windows任务栏的不同区域。?
1. 编程思想?
(1)任务栏窗体的窗口信息为:?
①任务栏的窗口类名是:ShellTrayWnd。?
②开始按钮的窗口类名是:Button。?
③应用程序切换区的窗口类名是:ReBarWindow32。?
④任务栏通知区的窗口类名是:TrayNotifyWnd。?
⑤任务栏时钟的窗口类名是:TrayClockWClass。?
(2)调用FindWindow函数得到任务栏的窗口句柄。?
(3)调用FindWindowEx函数得到任务栏各子区域的窗口句柄。?
(4)根据窗口句柄,调用ShowWindow函数控制任务栏各区域显示或隐藏 (show/hide);调用En ableWindow函数控制任务栏各区域有效或无效(enabled/disabled)。?
2. 编程方法?
(1)在Delphi3.0 IDE中新建工程Project1, Project1中包含Form1, 窗体如下图所示:
(2)定义窗口句柄数组:Wnd:array[0..4] of THandle;?
(3)GetHandles过程代码如下:?
procedure TForm1.GetHandles;?
begin? //得到Tray Bar的窗口句柄;? Wnd[0]:=FindWindow(′ShellTrayWnd′,nil);? //得到开始按钮的窗口句柄;? Wnd[1]:=FindWindow(′ShellTrayWnd′,nil);? Wnd[1]:=FindWindowEx(Wnd[1],HWND(0),′Button′,nil);? //得到应用程序切换区的窗口句柄;? Wnd[2]:=FindWindow(′ShellTrayWnd′,nil);? Wnd[2]]:=FindWindowEx(Wnd[2],HWND(0),′ReBarWindow32′,nil);? //得到任务栏通知区的窗口句柄;? Wnd[3]:=FindWindow(′ShellTrayWnd′,nil);? Wnd[3]:=FindWindowEx(Wnd[3],HWND(0),′TrayNotifyWnd′,nil);? //得到任务栏时钟的窗口句柄;? Wnd[4]:=FindWindow(′ShellTrayWnd′,nil);? Wnd[4]:=FindWindowEx(Wnd[4],HWND(0),′TrayNotifyWnd′,nil);? Wnd[4]:=FindWindowEx(Wnd[4],HWND(0),′TrayCLockWClass′,nil);? end;? |
(4)EnableOrDisable过程代码如下:?
procedure TForm1.EnableOrDisable(Sender:TOBject);?
begin? GetHandles;? if TCheckBox(Sender). Checked then? case TCheckBox(Sender). Tag of? 0: EnableWindow(Wnd[0], False);? 1: EnableWindow(Wnd[1], False);? 2: EnableWindow(Wnd[2], False);? 3: EnableWindow(Wnd[3], False);? 4: EnableWindow(Wnd[4], False);? end? else? case TCheckBox(Sender). Tag of? 0: EnableWindow(Wnd[0], True);? 1: EnableWindow(Wnd[1], True);? 2: EnableWindow(Wnd[2], True);? 3: EnableWindow(Wnd[3], True);? 4: EnableWindow(Wnd[4], True);? end;? end;? |
(5)HideOrShow过程代码如下:?
procedure TForm1.HideOrShow(Sender:TObject);?
begin? GetHandles;? if TCheckBox(Sender). Checked then? case TCheckBox(Sender). Tag of? 0: ShowWindow(Wnd[0],SWHIDE);? 1: ShowWindow(Wnd[1],SWHIDE);? 2: ShowWindow(Wnd[2],SWHIDE);? 3: ShowWindow(Wnd[3],SWHIDE);? 4: ShowWindow(Wnd[4],SWHIDE);? end? else? case TCheckBox(Sender). Tag of? 0: ShowWindow(Wnd[0],SWShow);? 1: ShowWindow(Wnd[1],SWShow);? 2: ShowWindow(Wnd[2],SWShow);? 3: ShowWindow(Wnd[3],SWShow);? 4: ShowWindow(Wnd[4],SWShow);? end;? end; |
?
(6)FormClose事件代码如下://将Windows任务栏恢复到正常状态;?
procedure TForm1.FormClose(Sender:TObject; var Action: TCloseAction);?
var i:Integer;? begin? for i:=0 to 4 do? begin? EnableWindow(Wnd[i],True);? ShowWindow(Wnd[i],SWShow);? end;? end;? |
需要用到的一个函数:
LONG SetWindowLong( HWND hWnd, int nIndex, LONG dwNewLong);
program Project;
uses
Forms, Windows,
ufrmMain in 'ufrmMain.pas' {frmMain};
{$R *.res}
begin
Application.Initialize;
SetWindowLong(Application.Handle,GWL_EXSTYLE,WS_EX_TOOLWINDOW);
Application.CreateForm(TfrmMain, frmMain);
Application.Run;
end.
Delphi 操作“任务栏”
一、windows任务栏常规
1、通常编译好的文件,执行后在任务栏中,只显示一个主窗口的“标题框(带图标)”。不管你进入那一个子窗口,只显示主窗口的“标题框”
2、程序通过进入托盘,只一托盘区显示一个图标,任务栏中,就隐藏了。
3、如果想一开始就取消任务栏主窗口的“标题框” ,e 可在窗口的Creat事件中,加入代码:
(1)Delphi7
SetWindowLong(Application.Handle, GWL_EXSTYLE, WS_EX_TOOLWINDOW); //隐藏
// SetWindowLong(Application.Handle, GWL_EXSTYLE, WS_EX_APPWINDOW); //显示
或
SetWindowLong(Self.Handle,GWL_EXSTYLE,WS_EX_TOOLWINDOW);
SetWindowLong(self.Handle,GWL_EXSTYLE,WS_EX_APPWINDOW);
(2)在程序的.dpr文件中create窗体前加入:
Application.ShowMainForm:=false; // 隐藏窗口
// Application.ShowMainForm:=true; // 显示窗口
(3)修改工程文件DPR中的“Application.MainFormOnTaskbar := True;”为“Application.MainFormOnTaskbar := False;”
在主窗体的 OnShow 事件中写下:ShowWindow(Application.Handle, SW_HIDE);
二、Windows任务栏的操作
1、隐藏Windows任务栏
procedure Tform1.Button1Click(Sender: TObject);
var wndHandle: THandle; //用于存储指定窗口的句柄
wndClass: array[0..50] of Char; //用于存储类名
begin
strPCopy(@wndClass[0], 'Shell_TrayWnd'); //获取任务栏类名
wndHandle := FindWindow(@wndClass[0],nil); //获取任务栏窗口的句柄
ShowWindow(wndHandle, SW_Hide); //隐藏Windows任务栏
end;
2、隐藏Windows任务栏
procedure Tform1.Button2Click(Sender: TObject);
var wndHandle: THandle; //用于存储指定窗口的句柄
wndClass: array[0..50] of Char; //用于存储类名
begin
strPCopy(@wndClass[0], 'Shell_TrayWnd'); //获取任务栏类名
wndHandle := FindWindow(@wndClass[0],nil); //获取任务栏窗口的句柄
ShowWindow(wndHandle, SW_Show); //显示Windows任务栏
end;
一.新建一个应用程序:File->New Applicaton 在Interface部分要放在Uses Message之后,定义一个消息常量:const WM_NID=WM_USER+1000; 系统规定从WM_USER开始为用户自定义消息。
二.定义一个全局变量: NotifyIcon:TNotifyIconData,NotifyIcon是非常重要的一个变量,整个程序基本上是围着这个变量在转。 TNotifyIconData是一个记录类型,按住Ctrl键,在TNotifyIconData 双击即进入ShellAPI.pas单元【注意加入引用】。(注:在Delphi中,这是一个非常好的对源代码进行分析的方法,源代码说明一切,你要想知道程序背后的内 幕,最好的方法就是分析源代码!)此时出现了以下赋值语句:
TNotifyIconData = TNotifyIconDataA,这个意思很明显,就是说TNotifyIconData和TNotifyIconDataA是同种数据类型,接着往下看有:
TNotifyIconDataA = _NOTIFYICONDATAA,意思与刚才的一样,再往下看:
type
_NOTIFYICONDATAA = record
cbSize: DWORD;
Wnd: HWND;
uID: UINT;
uFlags: UINT;
uCallbackMessage: UINT;
hIcon: HICON;
szTip: array [0..63] of AnsiChar;
end;
这可真是“千呼万唤始出来,犹抱琵琶半遮面”。现在大家很清楚了,我们刚才定义的全局变量NotifyIcon其实是一个包含有7个成分的记录类型变 量,就相当于C/C++中的结构体变量(C/C++的程序员应该是再熟悉不过了)。下面我们逐个来解释记录类型中的7个部分各有什么功能。
1> cbSize就是你定义的NotifyIcon变量的大小,用SizeOf(TNotifyIconData)可以取得,如果你是一个熟练的C/C++程 序员,你应该不会陌生。在C/C++中,每当要为一个结构体变量分配内存的时候都要:通过 SizeOf(Struct type) 来获知存放一个这样的结构体变量要多少内存。
2> Wnd是一个句柄,你希望托盘程序产生的消息有哪个窗体来处理就让Wnd指向那个窗体。
例如:你准备在任务栏的托盘小图标上单击时窗体是窗体在“显示”和“隐藏”之间切换,则把Wnd指向主窗体。
3> uID:如果你要创建多个托盘小程序,那么怎么区分它们呢?就是靠这个ID号来区分。
3> uFlags是一个标志位,它表示当前所创建的托盘程序具有哪些性质:
NIF_ICON 表示当前所设置的图标(即hIcon的值)是有效的
NIF_MESSAGE 表示当前所设置的系统消息(即uCallBackMessage的值)是有效的
NIF_TIP 表示当前所设置的提示条(即szTip的值)是有效的。
4> uCallBackMessage这是7个部分里面最重要的一个。这里指定一个回调消息,也就是说这里定义一个消息名,当你单击或者右击托盘图标的时候就 会向你在Wnd所指向的窗体发送一个在uCallBackMessage中定义的消息名,然后你在程序中定义一个消息出来函数来处理这个消息。这样就把 Windows关于消息的整套流程都处理好了。
6> hIcon为托盘图标的句柄,根据这个句柄你就可以增加、修改、删除图标。
7> szTip就是当你的鼠标放到任务栏托盘的小图标上的时候弹出来的提示信息。
三. 双击主窗体,进入FormCreate的代码区域:
TForm1.FormCreate(Sender:TObject);
Begin
//NotifyIcon为全局变量,在程序的开头已经定义了
with NotifyIcon do
begin
cbSize:=SizeOf(TNotifyIconData);
Wnd:=Handle; //指向当前窗体Form1的句柄
uID:=1;
uFlags:=NIM_ICON or NIM_MESSAGE or NIM_TIP;
uCallBackMessage:=WM_NID;
hIcon:=Application.Icon.Handle;
szTip:=‘Test 托盘’;
end;.
//把设置好的变量NotifyIcon加入到系统中以便处理
Shell_NotifyIcon(NIM_ADD,@NotifyIcon);
End;
四.接下来就是定义一个消息处理函数:系统给窗体发来了一个消息,就由下面这个函数来处理。每个消息处理函数都是处理某一类消息的,大家仔细地看看下面 函数体的定义和一般的函数定义有什么不一样:消息处理函数要在后面加上消息的名称,这样当系统发来WM_NID消息时,就是自动触发WMNID消息处理函 数。
procedure WMNID(var msg:TMessage);message WM_NID;
begin
case msg.LParam of
WM_LBUTTONUp; Form1.Visible:=not Form1.Visible;
WM_RBUTTONUP: ShowMessage(‘您点击的是右键’);
End;
End;
好了,一个最简单的程序诞生了,大家自己设置好自己喜欢的图标.
Project->Options,选中Application页面,在Icon项中加载自己喜欢的图标,这样程序运行时,在任务栏里显示 的就是 你喜欢的图标了。当你单击图标时,窗体Form1会在可见与不可见之间切换,也就是说单击一下显示,再单击一下又隐藏。当你右击图标的时候会弹出一条消 息:“你点击的是右键”。
五.最后要记住在关闭应用程序的时候要释放掉建立的托盘程序,否则会占用系统资源。
TForm1.FormDestroy(Sender:TObject);
Begin
Shell_NotifyIcon(NIM_DELETE,@NotifyIcon);
End;
【程序全部代码如下】
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs,ShellAPI;
const
WM_NID = WM_USER + 1000;
type
TForm1 = class(TForm)
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
procedure WMNID(var msg:TMessage);message WM_NID;
end;
var
Form1: TForm1;
NotifyIcon:TNotifyIconData;
implementation
{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject);
begin
//NotifyIcon为全局变量,在程序的开头已经定义了
with NotifyIcon do
begin
cbSize:=SizeOf(TNotifyIconData);
Wnd:=Handle; //指向当前窗体Form1的句柄
uID:=1;
uFlags:=NIF_ICON or NIF_MESSAGE or NIF_TIP;
uCallBackMessage:=WM_NID;
hIcon:=Application.Icon.Handle;
szTip:= 'Test';
end;
/ /把设置好的变量NotifyIcon加入到系统中以便处理
Shell_NotifyIcon(NIM_ADD,@NotifyIcon);
end;
procedure TForm1.WMNID(var msg:TMessage);
begin
case msg.LParam of
WM_LBUTTONUp: Form1.Visible:=not Form1.Visible;
WM_RBUTTONUP: ShowMessage('您点击的是右键');
End;
End;
procedure TForm1.FormDestroy(Sender: TObject);
begin
Shell_NotifyIcon(NIM_DELETE,@NotifyIcon);
end;
end.