`
javasogo
  • 浏览: 1816981 次
  • 性别: Icon_minigender_1
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

组件制作之五(托盘组件)

阅读更多

这将是最后一个组件了,目标定为非可视化,事实上非可视化组件要比可视化组件难做,因为是从TComponent继承而来,就没有了很多属性和事件。而这些都要我们从头来做过。

这个非可视化组件,我决定为托盘组件,其中用到的技术较多,我不如列一个表出来,然后再来讲解好一点。另外,可能篇幅会多一些,请耐心看。

用到的技术:

1作为核心功能,当然是托盘的应用啦。

2 托盘组件怎么样影响到主窗口最小化时隐藏

3 托盘如何处理消息

4 组件编辑器的用法

上面每一个技术都非常有趣,让我们一个个来看吧:

<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

托盘,是系统壳编程的一个功能,相信我们也看过很多啦,大概知道它用起来是什么样子的。

那么它是如何实现的呢,

Windows定义了这样一个结构来存放托盘的信息:

typedef struct _NOTIFYICONDATA { // nid

DWORD cbSize;

HWND hWnd;

UINT uID;

UINT uFlags;

UINT uCallbackMessage;

HICON hIcon;

char szTip[64];

} NOTIFYICONDATA, *PNOTIFYICONDATA;

cbSizeNOTIFYICONDATA结构的尺寸,我们一般用Sizeof就可以了

hWnd一个窗口句柄,用于检索托盘消息的。然而我们的非可视组件并没有窗口呀,这就是技术列表第三条要讲的,这里从略

uID 一标识托盘图标的,我们可以随便指定一个数,但如果同时有不同的图标,则数应该不同

uFlagsNIF_ICONNIF_MESSAGENIF_TIP中的一个或多个,我们全用就可以了。

uCallbackMessage;托盘消息,是我们自定义的消息,这里我们定义为:

const

WM_TrayMsg=WM_USER+10;

hIcon托盘图标句柄

szTip这个是托盘提示,当托盘出现时,鼠标移到哪里,就会出现该提示。

Delphi将这个结构重定义为TNotifyIconData,我们照这个来用就行了

我们应用托盘要用到API函数Shell_NotifyIcon,其中有两个参数,第一个为

NIM_ADDNIM_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

这样的意图是很明显的,因为当设计时的主窗其实是DelphiIDE,如果让他处理该消息,其实是处理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);

这样,窗口又回到了原来的风格,这时我们设FactiveFalse,则窗口就能正常最小化了。

到控件被释放时,我们一定要调用Application.UnhookMainWindow(AppMsgHook);来解除钩子

其实这里也有一个不完善的地方,应该再设一个成员变量,确定设置托盘时,窗口是正常最小化,还是最小化到看不见。而我没有这么做,直接如果FActiveTrue,最小化会出现托盘图标,并且窗口最小化到看不见。不过影响不大,有兴趣的朋友看了之后可以帮我完善一下,也当做自己的练习吗。

托盘如果处理消息,上面说到,要设置托盘结构,一定要有一个窗口句柄,才能检索托盘消息,那么这个句柄是什么呢,非可视组件没有窗口句柄呀。

如果你有看过TTimer的源码,一定知道这一句代码:

FWindowHandle := AllocateHWnd(WndProc);

它创建一个看不见的窗口,返回他的句柄,并指定WndProc为窗口的消息处理过程

我们何不效仿它呢。

于是也定义一个成员句柄:

FHandle: HWnd;

把该句柄赋给NOTIFYICONDATAhWnd字段

再定义一个消息处理过程:

procedure WndProc(var Msg: TMessage);

再在组件构造函数中:

FHandle := AllocateHWnd(WndProc);

如此之后,组件就可以截获托盘的消息了,并在WndProc过程中作相应处理。这里有必要对托盘的自定义消息做一个介绍:

我们自定义了这个消息WM_TrayMsg,它的lParam与托盘的uID相同,wParam是鼠标在图标上发生的事件消息,比如单击,双击等。

我们就要把这些消息转化为事件,供给用户处理,所以定义几个事件调度函数:

//以下为事件的调度函数

procedure DblClick; dynamic;

procedure Click; dynamic;

procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); dynamic;

procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); dynamic;

procedure MouseMove(Shift: TShiftState; X, Y: Integer); dynamic;

意思很明显,不多说,

当然也有几个事件方法指针:

FOnIconClick: TNotifyEvent;

FOnIconDblClick: TNotifyEvent;

FOnIconMouseMove: TMouseMoveEvent;

FOnIconMouseDown: TMouseEvent;

FOnIconMouseUp: TMouseEvent;

然后在WndProc中判断消息,并调用相应的事件调度函数。看代码吧,有解释。

好了,三个技术解决了,第四个呢,还是等代码出来以后再加组件编辑器吧。以下是源代码:

unit MyTray;

interface

uses

Windows, Messages, SysUtils, Classes, Graphics, Controls,

Forms, Dialogs, ShellApi, ExtCtrls,StdCtrls;

const

//自定义托盘消息

WM_TrayMsg=WM_USER+10;

type

//恢复窗口的方式,左双击,右双击,左单击,右双击

TRMode=(LDbClick,RDbClick,LCLick,RClick);

TMyTray=class(TComponent)

private

//私有成员

FIcon:TIcon; //图标

FDfIcon:THandle; //应用程序的默认图标

FSetDfIcon:Boolean; //是否用应用程序的图标,如果为True,则Ficonnil

FIconData: TNotifyIconData; //托盘数据结构

isMin:Boolean;//标识是否窗口最小化了

FHandle: HWnd; //不可视建窗体句柄,用于处理托盘事件

FActive: Boolean; //是否启用托盘

FHint: string; //托盘提示字符串

FRMode:TRMode; //恢复窗口的方式

isClickIn:Boolean;//标识鼠标是否点在图标上

OldStyleEX:longInt; //保存老的窗口风格

//事件成员

FOnIconClick: TNotifyEvent;

FOnIconDblClick: TNotifyEvent;

FOnIconMouseMove: TMouseMoveEvent;

FOnIconMouseDown: TMouseEvent;

FOnIconMouseUp: TMouseEvent;

//设置方法

procedure SetIcon(value:TIcon);

procedure SetDfIcon(value:boolean);

procedure SetActive(value:boolean);

procedure SetHint(value:string);

procedure SetRMode(value:TRMode);

//私有方法

procedure SetTray(Way:DWORD); //设置托盘样式,修改,删除,增加

function GetActiveIcon:THandle; //取得有用的图标句柄

protected

//应用程序的消息钩子,获得主窗口的最小化消息

function AppMsgHook(var Msg:TMessage):Boolean;

procedure WndProc(var Msg: TMessage);//不可视窗口的窗口过程

//以下为事件的调度函数

procedure DblClick; dynamic;

procedure Click; dynamic;

procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); dynamic;

procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); dynamic;

procedure MouseMove(Shift: TShiftState; X, Y: Integer); dynamic;

public

constructor Create(AOwner:TComponent);override;

destructor Destroy;override;

published

property Active:Boolean read FActive write SetActive default False;

property Icon:TIcon read FIcon write SetICon;

property SetDfIconed: boolean read FSetDfIcon write SetDfIcon default true;

property Hint:String read FHint write SetHint;

property RMode:TRmode read FRmode write SetRMode default LDbClick;

//事件的方法指针

property OnIconClick: TNotifyEvent read FOnIconClick write FOnIconClick;

property OnIconDblClick: TNotifyEvent read FOnIconDblClick write FOnIconDblClick;

property OnIconMouseMove: TMouseMoveEvent read FOnIconMouseMove write FOnIconMouseMove;

property OnIconMouseDown: TMouseEvent read FOnIconMouseDown write FOnIconMouseDown;

property OnIconMouseUp: TMouseEvent read FOnIconMouseUp write FOnIconMouseUp;

end;

procedure Register;

implementation

procedure Register;

begin

RegisterComponents('Wind', [TMyTray]);

end;

///////////TmyTray////////////////////////////

constructor TMyTray.Create(AOwner:TComponent);

begin

inherited Create(AOwner);

//设置程序钩子,指定AppMsgHook为处理函数,

//,应用程序的任何消息都将经过这个函数

Application.HookMainWindow(AppMsgHook);

FICon:=TICon.Create;

//得到默认图标的句柄,图标为应用程序的图标

FDfIcon:=Application.Icon.Handle;

FSetDfIcon:=True;

FActive:=False;

FRMode:=LDbClick;

isMin:=False;

//创建一个不可视窗口,并指定窗口过程,以处理托盘事件

FHandle := AllocateHWnd(WndProc);

//保存窗体的老的风格,在恢复窗口的同时也恢复原来的窗口风格

OldStyleEX:=GetWindowLong(Application.Handle,GWL_EXSTYLE);

end;

destructor TMyTray.Destroy;

begin

Application.UnhookMainWindow(AppMsgHook);

//对象释放之前先消除托盘

SetTray(NIM_DELETE);

//释放不可能窗口的句柄

DeallocateHWnd(FHandle);

FICon.Free;

inherited Destroy;

end;

//应用程序钩子,可以截获应用程序的所有消息

function TMyTray.AppMsgHook(var Msg:TMessage):Boolean;

var placement:WINDOWPLACEMENT;

begin

Result:=False;

//保证程序不会在设计时处理最小化消息

if not (csDesigning in ComponentState) then

if (Msg.Msg=WM_SYSCOMMAND) and(FActive) then

begin

if msg.WParam=SC_MINIMIZE Then

begin

//设置了这个属性后,窗口最小化就不会停在任务栏了,而是停在屏幕,

//位置由SetWindowPlacement来决定

ShowWindow(Application.Handle,SW_HIDE);

SetWindowLong(Application.Handle,GWL_EXSTYLE ,WS_EX_TOOLWINDOW);

GetWindowPlacement(Application.Handle,@placement);

placement.flags:=WPF_SETMINPOSITION;

placement.ptMinPosition.x:=1050;

placement.ptMinPosition.y:=800;

SetWindowPlacement(Application.Handle,@placement);

SetTray(NIM_ADD );

end;

end;

end;

procedure TMyTray.SetIcon(Value:TIcon);

begin

FIcon.Assign(Value);

FsetDfIcon:=False; //有了自定义的图标,则默认图标自动设为False

if FIcon.Empty then

FsetDfIcon:=True;

if (isMin)and(Factive) then

SetTray(NIM_MODIFY );

end;

//设置是否为默认图标,FIcon为互相的变量,只能有其中一个

procedure TMyTray.SetDfIcon(Value:Boolean);

begin

if FSetDfIcon<>Value then

begin

FSetDfIcon:=Value;

if not FSetDfIcon then

begin

if FIcon.Empty then begin

FSetDfIcon:=True;

exit;

end;

end

else begin

if (IsMin)and(FActive) then

SetTray(NIM_MODIFY);

end;

end;

end;

procedure TMyTray.SetActive(Value:Boolean);

begin

if FActive<>Value then

begin

FActive:=Value;

end;

end;

procedure TMyTray.SetHint(Value:String);

begin

if FHint<>Value then

begin

FHInt:=Value;

if (IsMin)and(FActive) then

SetTray(NIM_MODIFY);

end;

end;

procedure TMyTray.SetRMode(Value:TRMode);

begin

if FRmode<>Value then

FRmode:=Value;

end;

//设置托盘方式,显示,修改,删掉,重要方法

procedure TMyTray.SetTray(Way:DWORD);

begin

FIconData.cbSize:=Sizeof(FIconData);

FIconData.Wnd:=FHandle;

FIConData.uID:=0;

FIConData.uFlags:=NIF_ICON or NIF_MESSAGE or NIF_TIP;

FIConData.uCallbackMessage:=WM_TrayMsg;

FIConData.hIcon:=GetActiveIcon;

StrLCopy(FIConData.szTip,Pchar(FHint),63);

Shell_NotifyIcon(Way,@FIconData);

end;

//取得可用的图标

function TMyTray.GetActiveIcon:THandle;

begin

if not FSetDfIcon then

result:=FIcon.Handle

else

result:=FDfIcon;

end;

//托盘消息的截获,以调用相应的事件调度方法

procedure TMyTray.WndProc(var Msg: TMessage);

var p:TPoint;

begin

if (Msg.Msg=WM_TrayMsg)and(FActive) then

begin

case Msg.LParam of

WM_LBUTTONDBLCLK://左双击

begin

GetCursorPos(p);

DblClick;

MouseDown(mbLeft, KeysToShiftState(TWMMouse(Msg).Keys)+[ssDouble], P.X, P.Y);

if FRmode=LDbclick then

begin

ShowWindow(Application.Handle,SW_SHOW);

//这里很重要的一个就是恢复窗口风格,不然下次把Active设为True

//最小化后,窗口依然会往左下角飞去,而托盘图标却看不见了.

SetWindowLong(Application.Handle,GWL_EXSTYLE ,OldStyleEX);

SendMessage(Application.Handle,WM_SYSCOMMAND,SC_RESTORE,0);

SetTray(NIM_DELETE);

end;

end;

WM_RBUTTONDBLCLK://右双击

begin

GetCursorPos(P);

DblClick;

MouseDown(mbRight, KeysToShiftState(TWMMouse(Msg).Keys)+[ssDouble], P.X, P.Y);

if FRmode=RDbclick then

begin

ShowWindow(Application.Handle,SW_SHOW);

SetWindowLong(Application.Handle,GWL_EXSTYLE ,OldStyleEX);

SendMessage(Application.Handle,WM_SYSCOMMAND,SC_RESTORE,0);

SetTray(NIM_DELETE );

end;

end;

WM_MOUSEMOVE: //鼠标移动

begin

GetCursorPos(P);

MouseMove(KeysToShiftState(TWMMouse(Msg).Keys), P.X, P.Y);

end;

WM_LBUTTONDOWN: //左单击下

begin

GetCursorPos(P);

IsClickIn:=True;

分享到:
评论

相关推荐

    delphi 制作托盘图标程序

    在Delphi编程环境中,制作一个具有托盘图标的程序是一项常见的任务,这使得应用程序可以在系统托盘区域运行,提供一种更隐蔽、不占桌面空间的用户界面。下面将详细讲解如何利用Delphi来实现这样的功能。 首先,我们...

    Labview制作托盘程序

    在描述中提到的"Labview制作托盘程序"是指利用Labview创建一个能够在操作系统任务栏通知区域(托盘区)运行的应用程序,就像许多常见的软件如QQ那样,最小化时会隐藏到系统托盘而不是彻底消失在用户的视野中。...

    电信设备-摄影机镜头模块制作用托盘组件.zip

    这个名为"电信设备-摄影机镜头模块制作用托盘组件.zip"的压缩包文件,显然包含了关于这类组件的详细资料,特别是"摄影机镜头模块制作用托盘组件.pdf"这一文档,很可能是设计图纸、生产工艺说明或者是技术规格书。...

    VC++6.0制作系统托盘

    这个结构是Windows API中的一个重要组件,用于设置和管理托盘图标。它包含了关于托盘图标的各种信息,如图标索引、提示文本、关联菜单等。以下是一些`NOTIFYICONDATA`结构的关键字段: 1. `hWnd`:窗口句柄,表示与...

    参考学习托盘移载组件模型

    本文将深入探讨“参考学习托盘移载组件模型”这一主题,这是一份基于SOLIDWORKS软件创建的3D模型,旨在为用户提供一个交流和学习的平台。 首先,我们要了解“托盘移载组件模型”。在工业自动化系统中,托盘移载装置...

    电信设备-一种显示面板组件的托盘.zip

    在电信设备领域,显示面板组件的托盘是关键部件之一,它主要负责承载、固定以及保护显示面板在运输和安装过程中的完整性。本文件“一种显示面板组件的托盘”详细探讨了这种特殊托盘的设计原理、制造工艺以及在实际...

    系统托盘制作delphi

    总的来说,利用Delphi制作系统托盘程序涉及到的主要步骤包括:添加`TTrayIcon`组件,设置其属性,处理窗体关闭事件,创建并绑定右键菜单,以及利用组件提供的事件进行功能扩展。通过以上方法,你可以创建出一款功能...

    VB制作托盘运行的程序!

    总结来说,VB制作托盘运行的程序主要涉及以下几个步骤:添加第三方控件,设计界面,处理托盘事件,编写逻辑代码,以及最后的测试和优化。这样的程序对于需要后台运行或低调运行的应用来说非常实用,同时也能提供用户...

    电信设备-打印托盘组件及含其的3D打印设备.zip

    打印托盘组件是3D打印设备的核心部分之一,它承载着打印材料,并在打印过程中提供稳定的支撑。在电信设备中,这种组件往往需要具备高精度、耐高温以及良好的机械性能,以确保设备在严苛的工作环境下仍能正常运行。3D...

    制作window系统的 托盘图标源代码

    在制作托盘图标时,我们主要会用到以下几个关键组件和步骤: 1. **CWinApp类**:这是MFC应用程序的核心类,通常继承自CWinApp。你需要在这个类的派生类中初始化托盘图标,并处理系统消息。 2. **C TrayIcon类**:...

    delphi系统托盘制作_源码

    ### Delphi系统托盘制作概述 #### 1. **理解系统托盘图标** 系统托盘图标允许用户快速访问程序功能,如最小化到托盘、显示快捷菜单等。在Delphi中实现这一点需要利用`Shell_NotifyIcon()`函数与自定义类来处理事件...

    DELPHI做的托盘程序

    DELPHI制作的托盘程序是一种利用Windows操作系统API在任务栏通知区域(通常称为系统托盘)运行的应用程序。在Windows环境下,托盘程序能够提供一个小型图标,用户可以通过这个图标进行各种操作,而不必打开应用程序...

    VB制作托盘动态图标教程

    在VB(Visual Basic)编程环境中,制作托盘动态图标是一项常见的任务,这主要涉及到系统托盘区域的应用程序设计。系统托盘,也被称为通知区域,是位于Windows操作系统任务栏右下角的小图标集合,通常用于后台运行的...

    Delphi 实现最小化托盘控件

    TTrayIcon 是 Delphi VCL 库中的一个组件,它允许应用程序在任务栏的系统托盘区域显示图标。当用户点击该图标时,可以触发相应的事件,例如显示一个上下文菜单或者恢复应用程序的主窗口。在提供的示例代码中,我们有...

    系统托盘自定义图标工具(附C++源码)

    它提供了丰富的API和组件,使得开发者能够方便地创建美观、功能丰富的GUI应用。在Qt中,实现系统托盘功能主要涉及`QSystemTrayIcon`类。这个类提供了创建、显示和管理托盘图标的接口,同时支持设置图标、添加上下文...

    delphi 实现闪动、动画、托盘的源码

    通过`FlashWindow`实现窗口闪动,利用TTimer和控件属性变化制作动画效果,以及使用TTrayIcon组件管理托盘图标,开发者可以轻松地为应用程序增添更多特色和交互性。以上代码示例只是基础用法,实际开发中还可以根据...

    Delphi制作最小化到系统托盘的程序&TForm1.FormDestroy不执行的原因.zip_win10程序窗口最小化不见了

    同时,为了在系统托盘区显示右键菜单或者响应双击事件,我们需要为TTrayIcon组件添加相应的代码。例如,添加一个ShowMainForm菜单项,当用户点击该菜单时,恢复窗体显示: ```delphi procedure TForm1.TrayIcon1...

    Visaul C#托盘程序制作心得

    在Windows Forms应用程序中,`NotifyIcon`控件是实现托盘程序的核心组件。它允许你在任务栏的通知区域显示一个图标,并且可以关联一个上下文菜单或鼠标事件处理。在代码中,我们首先定义了一个`NotifyIcon`类型的...

    VB制作托盘运行小闹钟源码

    【VB制作托盘运行小闹钟源码】是一个基于Visual Basic(VB)开发的简易应用程序,它能够在系统托盘区运行并实现定时提醒功能。这个项目对于初学者来说是一个很好的学习资源,因为它提供了源代码,使得用户可以直接...

    FTP上传oracle数据,安装包的制作及托盘的使用

    FTP上传Oracle数据、安装包制作以及托盘应用是IT领域中的常见操作,这些技术在软件开发和系统集成中起着至关重要的作用。以下是对这些知识点的详细解释: 1. FTP上传Oracle数据: FTP(File Transfer Protocol)是...

Global site tag (gtag.js) - Google Analytics