学海荡舟手机网

主页 > 实用文摘 > 教育文摘_02 > > 详细内容

应用程序指示图标的实现方法研究_信息技术论文

应用程序指示图标的实现方法研究

 

          蒋俊杰  石波  潘若愚(合肥工业大学网络所    230009)

摘要:本文较详细地介绍了windows环境下的应用程序指示图标的基本原理及其实现方法,并给出了通过delphi编程环境实现的应用程序指示图标的实例.

关键词:指示图标  delphi

1.引言

    在早期的dos操作系统中,存在着一类特殊的程序—内存驻留程序(tsr),这类程序始终驻留在内存中,当需要使用时就直接从内存中调用,大大提高了时间效率,而这类程序一般的也是系统需要频繁调用的程序或是一个实时监控程序,因此通过驻留内存来换取时间效率是值得的.

    在windows环境下也需要这一类程序,一些是系统程序如输入法和系统时钟,一些是应用程序如一些实时监控的杀毒软件等,这些程序通常都是一直伴随着系统运行的,它们在运行时一般不需要或很少需要用户的干预, 而windows环境下的应用程序在运行时通常都是以窗口形式存在的,即使最小化也会在任务栏上留下一个带图标及标题的按钮,又由于windows是多任务操作系统,用户几乎肯定会同时进行其他操作,因此象上述应用程序若不采取其他措施就必然会影响到用户的其他操作或者是程序自身容易受到意外的用户干预,影响了正常运行.

    可喜的是,从windows 95 和 windows nt 4.0开始,出现了一个令人振奋的特性:任务栏指示区.这个通常位于任务条右端的区域能包含一种称作指示图标(notifyicon)的小图标(如输入法图标、系统时钟图标等),通过这些图标能够引出复杂的应用程序或菜单,而具有了这种图标的应用程序也就不存在上面所讲的问题了.本文将介绍windows环境下应用程序指示图标的基本原理及其实现方法,并给出通过delphi编程环境实现的应用程序指示图标的实例.

2.基本原理

    要实现应用程序指示图标,首先需要创建一个应用程序窗口,再注册一个图标到任务栏,并设置它的消息循环(使图标与某个应用程序窗口关联),最后还应在程序退出时关闭该指示图标,这就是整个应用程序指示图标实现过程的基本步骤,当然还有很多具体的细节上的工作.下面就介绍一些比较关键的基本原理及技术细节.

在windows系统中存在这样一个基本的数据结构: tnotifyicondata,它是一个用来设置窗口句柄的数据结构,是一个记录类型的参数,其具体结构如下:

    type

        tnotifyicondata = record

            cbsize: dword;

            hwnd: hwnd;

            uid: uint;

            uflags: uint;

            ucallbackmessage: uint;

            hicon: hicon;

            sztip: array [0..63] of ansichar;

    end;

要实现指示图标首先就需要设置这个图标的窗口句柄(这将定义哪个窗口处理消息循环),回调消息号,图标,工具提示等,这也是所有工作的关键.一旦这个数据结构设置了,我们就可以增加一个图标到任务栏上的指示区了,同时将该图标与一个窗口(应用程序)关联了起来.

    下面就简要介绍上述数据结构中的各个成员:

·cbsize是该结构的大小(由系统用来确定版本);

·hwnd是一个窗口句柄,用来指示icon向该窗口发送消息,即将icon与该窗口关联了起来;

·uid是图标标识符,仅当程序有多个图标时才有用, 它是用于区分各个图标的;

·uflags有三个可能的标志: nif_message、nif_icon及nif_tip.它是用来说明该结构的hicon、ucallbackmessage和sztip这三个成员中哪一个或哪几个的设置值有效;

·ucallbackmessage是应用程序定义的一个消息标识符(通常是使用系统消息作为回调消息,因此一般用系统消息标识符即可),系统通过该消息标识符来将用户对指示图标的操作消息发送到由hwnd定义的窗口,通过该标识符的lparam参数可判断是何种操作从而进行相应处理;

·hicon是要在指示区内新增、删除或修改的icon图标的句柄;

·sztip是当用户将鼠标移到任务栏中的指示图标上时,所显示出的提示文本.

    在声明了上述的数据结构类型变量并对其各个分量进行了设置后,就可以向系统注册该指示图标了.指示图标的注册是通过调用shell_notifyicon这个api函数来实现的,该api函数的语法声明如下:

    winshellapi bool winapi shell_notifyicon(

            dword dwmessage,    // message identifier

            pnotifyicondata pnid    // pointer to structure

        ); 

该函数的功能就是向系统发送一条消息用以在任务栏指示区新增、修改或删除一个图标.其中的参数dwmessage是一个消息标识符,用来标识向系统发送的消息类型,这个参数有三种取值:nim_add、nim_delete和nim_modify,它们分别表示向指示区新增、删除、修改一个图标.参数pnid 是一个指向tnotifyicondata结构的指针,通过该参数使所发送的消息与一个具体的应用程序指示图标关联起来,实现对该图标的新增、修改、删除.这样就可以在应用程序启动时进行新增指示图标的操作,在退出应用程序时删除指示区的相应指示图标.

    当然在应用程序窗口中还得有一个消息处理程序用来处理由shell_notifyicon函数发回的消息,也就是应用程序应能响应用户对指示图标的鼠标操作.另外,为了真正解决在本文引言中提到的问题,应用程序窗口还应根据需要在运行时实现隐藏,而只有通过对指示图标操作才能使其再现,最小化时又可隐藏,这可以通过调用api函数showwindow来实现,通过对其指定不同的参数来实现窗口的隐藏和再现, 在delphi中要实现程序启动时窗口的不可见,可以在程序的窗体创建程序里设置application的showmainform属性为false即可.

3.应用实例:

   下面介绍本人开发的一个ic卡考勤系统中应用程序指示图标的实现作为上述实现方法的一个实例并给出了部分源代码.由于ic卡读卡机功能上存在一些不足,在读卡时不能自己发送”中断”信号到微机,因此微机需要对读卡机进行实时监控,通过检测得知ic读卡机中是否有卡并决定是否进行读卡或其他操作,所以在该系统中采用了应用程序指示图标的技术,并取得了较好的效果..

    首先为了使用api函数shell_notifyicon及结构tnotifyicondata,必须在程序的uses语句中添加声明shellapi单元,然后需要向窗体类的元素中添加一个tnotifyicondata结构,如下:

        private

                nid: tnotifyicondata;

在窗体的创建程序中设置该结构的各个成员值:

        nid.cbsize := sizeof(nid);

            nid.wnd := handle;      //当前窗体的句柄

            nid.uid := 1;

            nid.ucallbackmessage := wm_rbuttondown;

            nid.hicon := loadicon(hinstance,'kq');

            nid.sztip := 'hs考勤系统';

        nid.uflags := nif_message or nif_icon or nif_tip;

其中函数loadicon()用于装载一个图标资源, 参数hinstance为应用程序句柄,第二个参数串值用于指定图标文件名或是图标资源标识符.

    再调用api函数shell_notifyicon向任务栏指示区添加一个图标:

        shell_notifyicon(nim_add,@nid);

并且设置应用程序的showmainform属性为false使得应用程序窗体在启动时即不可见:

        application.showmainform := false;

    为了使应用程序能够对用户在指示图标上的操作有所响应,需要在应用程序窗体中建立一个消息处理函数icontray.首先是向窗体类的元素中添加一个该过程声明:

        public

                    { public declarations }

                    procedure icontray(var msg:tmessage);

                              message wm_rbuttondown;

其次就需要在该窗体的implementation

  


部分定义该消息处理函数的具体实现过程:

        procedure tform1.icontray(var msg: tmessage);

var pt: tpoint;

i : byte;

begin

            case msg.lparam of      //根据lparam