|
这将是最后一个组件了,目标定为非可视化,事实上非可视化组件要比可视化组件难做,因为是从TComponent继承而来,就没有了很多属性和事件。而这些都要我们从头来做过。
这个非可视化组件,我决定为托盘组件,其中用到的技术较多,我不如列一个表出来,然后再来讲解好一点。另外,可能篇幅会多一些,请耐心看。
用到的技术:
1作为核心功能,当然是托盘的应用啦。
2 托盘组件怎么样影响到主窗口最小化时隐藏
3 托盘如何处理消息
4 组件编辑器的用法
上面每一个技术都非常有趣,让我们一个个来看吧:
一 托盘,是系统壳编程的一个功能,相信我们也看过很多啦,大概知道它用起来是什么样子的。
那么它是如何实现的呢,
Windows定义了这样一个结构来存放托盘的信息:
typedef struct _NOTIFYICONDATA { // nid
DWORD cbSize;
HWND hWnd;
UINT uID;
UINT uFlags;
UINT uCallbackMessage;
HICON hIcon;
char szTip[64];
} NOTIFYICONDATA, *PNOTIFYICONDATA;
cbSize是NOTIFYICONDATA结构的尺寸,我们一般用Sizeof就可以了
hWnd一个窗口句柄,用于检索托盘消息的。然而我们的非可视组件并没有窗口呀,这就是技术列表第三条要讲的,这里从略
uID 唯 一标识托盘图标的,我们可以随便指定一个数,但如果同时有不同的图标,则数应该不同
uFlags是NIF_ICON,NIF_MESSAGE,NIF_TIP中的一个或多个,我们全用就可以了。
uCallbackMessage;托盘消息,是我们自定义的消息,这里我们定义为:
const
WM_TrayMsg=WM_USER+10;
hIcon托盘图标句柄
szTip这个是托盘提示,当托盘出现时,鼠标移到哪里,就会出现该提示。
Delphi将这个结构重定义为TNotifyIconData,我们照这个来用就行了
我们应用托盘要用到API函数Shell_NotifyIcon,其中有两个参数,第一个为
NIM_ADD,NIM_DELETE ,NIM_MODIFY中的一个,分别表示添加托盘(图标出现)
修改托盘(比如图标,提示),删除(图标消失)第二个参数是NOTIFYICONDATA的指针
嗯,托盘应该差不多了。
二 这个组件能够决定主窗体最小化时,是否是正常最小化并没有托盘图标。还是最小化到屏幕之外,使我们看不见,且托盘区出现了图标。这里有一个成员为FActive来决定。
那么我们是怎么样影响到主窗体呢,也即怎么截获窗体的最小化消息呢。
全局变量Application有一个方法为procedure HookMainWindow(Hook: TWindowHook);
顾名思义,就是钩到主窗口的所有消息。里面的参数是TWindowHook类型,它是一个方法指针,定义如下:
type TWindowHook = function(var Message: TMessage): Boolean of object;
我们要自己定义过程的,然后传给HookMainWindow:
function AppMsgHook(var Msg:TMessage):Boolean;
Application.HookMainWindow(AppMsgHook);
这样做之后,主窗口的所有消息都会经过AppMsgHook方法啦,最小化消息也不例外,则我们可以在里面截获这个消息,并做一些操作:
做什么操作呢,先判断组件是否为设计时,如果是,不进行操作,如果不是进行下一步
if not (csDesigning in ComponentState) then
这样的意图是很明显的,因为当设计时的主窗其实是Delphi的IDE,如果让他处理该消息,其实是处理IDE的最小化消息,这时如果你最小化IDE,就会出现托盘啦。所以不能。
下一步是是否截获了最小化消息,以及FActive是否为真:
if (Msg.Msg=WM_SYSCOMMAND) and(FActive) then
两样都成立,执行里面的代码,代码中有解释,这里只说两个:
SetWindowLong(Application.Handle,GWL_EXSTYLE ,WS_EX_TOOLWINDOW);
设置了这个属性后,窗口最小化就不会停在任务栏了,而是停在屏幕的某个位置,这个位置在哪里呢,由
placement.flags:=WPF_SETMINPOSITION;
placement.ptMinPosition.x:=1050;
placement.ptMinPosition.y:=800;
SetWindowPlacement(Application.Handle,@placement);
决定,具体的看代码,自己查帮助吧,这里不多说
而上说的设置SetWindowLong后,问题来了,窗口最小化的风格一变了,当你把Factive设为False,再最小化窗口,此时是没有托盘图标,但窗口还是最小化到屏幕的那个位置去了,我们看不到,又不能使其恢复(没有托盘)。怎么办呢,
原来还有一个GetWindowLong函数会返回当前风格的值,我们可以在控件的构造函数中这样调用
OldStyleEX:=GetWindowLong(Application.Handle,GWL_EXSTYLE);
这时,OldStyleEX:就保存了窗口原来最小化的风格了,窗口最小化,调用SetWindowLong,设置了新的最小风格。而当我们触发托盘事件,使窗体恢复大小时,我们在处理函数中调用
SetWindowLong(Application.Handle,GWL_EXSTYLE ,OldStyleEX);
这样,窗口又回到了原来的风格,这时我们设Factive为False,则窗口就能正常最小化了。
到控件被释放时,我们一定要调用Application.UnhookMainWindow(AppMsgHook);来解除钩子
其实这里也有一个不完善的地方,应该再设一个成员变量,确定设置托盘时,窗口是正常最小化,还是最小化到看不见。而我没有这么做,直接如果FActive为True,最小化会出现托盘图标,并且窗口最小化到看不见。不过影响不大,有兴趣的朋友看了之后可以帮我完善一下,也当做自己的练习吗。
[1] [2] [3] [4] [5] [6] [7] 下一页 |