1、第十二章 Win32环境程序设计这一章节可以说是本书精华之一,Win32程序设计算是比较复杂的部分,但是我们以最简单的叙述带领着大家进入Win32程序设计的殿堂,让你写出来的程序具有一定的水平以上。若能将本章与下一章的技巧灵活运用,更能让大家写出高阶的窗口程序。1大纲 12-1.档案总管的接口 12-2.标头控制组件 12-3.进度状态显示组件 12-4.轨迹追踪列 12-5.上下控制组件 12-6.日期时间 12-7.热键组件的使用(HotKey)12-8.常驻在System Tray的程序 本章习题212-1.档案总管的接口 提到Win32的程序设计,最重要的范例就是档案总管。整个档案总管
2、都是使用Win32的接口来完成。而我们在这一章以及下一章,也都会围绕着档案总管来介绍大部分内容。下图中就是档案总管的接口,在这个接口里,主要组件有ListView、TreeView、Splitter、以及StatusBar这四种VCL组件,SplitterTreeViewListViewStatusBar312-1.档案总管的接口 窗体检视组件(ListView)范例12-1 在范例12-1,我们的接口相当简单,除了一个输入数据的接口外,就是一个ListView。除了提到这些可看见的VCL组件外,我们还有放入一个Popup menu以及一个ImageList在这个范例中。Popup menu主
3、要是提供鼠标右键的功能选单,而ImageList则是要提供一些Image给ListView使用。412-1.档案总管的接口 窗体检视组件(ListView)新增Column个数512-1.档案总管的接口 窗体检视组件(ListView)ViewStyle的不同 大图示(vsIcon)小图示(vsSmallIcon)清单(List)详细列表(Report)612-1.档案总管的接口 窗体检视组件(ListView)范例12-1执行结果712-1.档案总管的接口 树状检视组件(TreeView)TreeView是目前档案总管中的重要组件之一,在档案总管中TreeView负责显示从桌面开始的所有树状
4、结构。在这一小节里,我们将会利用三个范例让各位练习TreeView的各项使用实例。谈到Tree的使用,就必须谈到什么是根节点、父节点、子节点、以及叶节点。根节点就是我们所谓的root,他是在整个Tree的最上方,以档案总管来说,根节点就是桌面 父节点就是这个节点的底下还有一个以上的节点 子节点就是这个节点的上一层还有节点 叶节点就代表这个节点已经是这支树的最后一个节点812-1.档案总管的接口 树状检视组件(TreeView)范例12-2:利用简单的程序来控制TreeView的各项动作。我们主要是使用静态的方式将一棵树建立起来。这棵树是利用BCB提供的接口去产生。912-1.档案总管的接口 树
5、状检视组件(TreeView)范例12-2执行结果1012-1.档案总管的接口 树状检视组件(TreeView)范例12-3:在程序中建构一个静态的TreeView 在范例12-3,我们也是静态产生Tree,但是这次我们不是从BCB的接口中产生,我们是从程序代码中产生。在范例12-3的接口中,全部都跟范例12-2一模一样。程序中,我们宣告了三个TreeNode(两个也可以),经由这三个TreeNode之间的相互关系,我们完成了整颗树的建立。在建树的程序代码方面并不难,比较特别的就是要回到上一层我们使用的是parent=parentParent这样的方法来取得上一层Node的内存地址。至于一开始
6、我们有保留Root的地址这只是一个习惯,因为从BCB中也是可以判断哪个Node是Root,在范例12-3中这样做只是为了方便以及写程序者的习惯。1112-1.档案总管的接口 树状检视组件(TreeView)范例12-3:程序代码void _fastcall TForm1:FormCreate(TObject*Sender)TTreeNode*root,*parent,*son;root=TreeView1-Items-Add(NULL,Root);root-ImageIndex=0;root-SelectedIndex=1;root-StateIndex=-1;parent=root;son=
7、TreeView1-Items-AddChild(parent,Parent1);son-ImageIndex=2;son-SelectedIndex=3;son-StateIndex=-1;parent=son;son=TreeView1-Items-AddChild(parent,Son_1_1);son-ImageIndex=2;son-SelectedIndex=3;son-StateIndex=0;son=TreeView1-Items-AddChild(parent,Son_1_2);son-ImageIndex=2;son-SelectedIndex=3;son-StateInd
8、ex=-1;parent=parent-Parent;son=TreeView1-Items-AddChild(parent,Parent2);son-ImageIndex=2;son-SelectedIndex=3;son-StateIndex=-1;parent=son;son=TreeView1-Items-AddChild(parent,Son_2_1);son-ImageIndex=2;son-SelectedIndex=3;son-StateIndex=-1;parent=son;son=TreeView1-Items-AddChild(parent,Son_2_1_1);son-
9、ImageIndex=2;son-SelectedIndex=3;son-StateIndex=1;parent=parent-Parent-Parent;son=TreeView1-Items-AddChild(parent,Parent3);son-ImageIndex=2;son-SelectedIndex=3;son-StateIndex=-1;1212-1.档案总管的接口 树状检视组件(TreeView)范例12-4:在程序中建构一个TreeView,主要程序代码我们分成三个部分 第一部份是动态新增所需要的变量宣告,这部分是宣告在main.cpp的上方,归类于全域变数 第二部份就是有
10、关新增删除TreeNode部分的程序代码 最后一部分就是一些琐碎的功能,这些程序代码包括了展开以及收合的功能,也有在StatusBar上面显示目前的状况,还有一个就是选择要不要显示Root。1312-1.档案总管的接口 树状检视组件(TreeView)范例12-4:程序代码 宣告/宣告两个变量.用来存放Root Address和Node的AddressTTreeNode*root=NULL;TTreeNode*node=NULL;1412-1.档案总管的接口 树状检视组件(TreeView)范例12-4:程序代码 动态新增Nodevoid _fastcall TForm1:N1Click(TO
11、bject*Sender)/新增一个Node,在新增的时候会自动判断是不是新增Root,在新增的时候利用InputQuery来当作输入接口AnsiString Buf;if(root=NULL)/如果现在root还是NULL的话.表示要新增一个rootif(InputQuery(输入,请输入TreeNode的名称,Buf)/使用InputQuery当作输入接口root=TreeView1-Items-AddChild(NULL,Buf);/将新增的Node加入到TreeView中root-ImageIndex=0;root-SelectedIndex=1;root-StateIndex=-1;
12、/设定该Node的一些基本属性StatusBar1-SimpleText=新增 Root 节点;/在StatusBar显示目前的运作情况TreeView1-AlphaSort();/新增之后利用AlphaSort对整个Tree排序else /新增一般的Node/必须得先选一个node才能继续产生Child,不然如果没有Parent那来的Childif(TreeView1-Selected!=NULL)/使用InputQuery当作输入接口if(InputQuery(输入,请输入TreeNode的名称,Buf)/将新增的Node加入到TreeView中node=TreeView1-Items-A
13、ddChildFirst(TreeView1-Selected,Buf);node-ImageIndex=2;node-SelectedIndex=3;node-StateIndex=-1;/设定该Node的一些基本属性StatusBar1-SimpleText=新增一个 Node;/在StatusBar显示目前的运作情况TreeView1-AlphaSort();/新增之后利用AlphaSort对整个Tree排序1512-1.档案总管的接口 树状检视组件(TreeView)范例12-4:程序代码 动态删除Nodevoid _fastcall TForm1:N2Click(TObject*Se
14、nder)if(TreeView1-Selected!=NULL)/如果有Node被选取.也选择要删除才执行if(TreeView1-Selected=root)/判断是不是RootTreeView1-Selected-Delete();root=NULL;/如果是root被删除.要将root的point设成nullStatusBar1-SimpleText=删除 Root 节点;else TreeView1-Selected-Delete();StatusBar1-SimpleText=删除一个 Node;1612-1.档案总管的接口 树状检视组件(TreeView)Sort AlphaSo
15、rt:根据我们每个Node的Caption中的值去做排序 CustomSort:让我们自己写函式去做排列 SortType stBoth:当Date或是Text有任何一种改变时就重新Sort stDate:当Node的数据改变时就重新Sort一次 stNone:永远不排序 stText:当Node的Text改变时重新Sort1712-1.档案总管的接口 分隔组件(Splitter)分隔组件最主要的功能就是让两个组件在你拉动的时候自动分配组件的大小。例如在档案总管中,我们可以将光标停放在TreeView和ListView的中间,接着游标就会变成一个双箭头的光标,然后我们就可以按着鼠标的左键左右移
16、动鼠标,这时候TreeView和ListView的窗口会随着鼠标的移动自动改变大小。拉动之后可以自动调整大小1812-1.档案总管的接口 状态列组件(StatusBar)顾名思义就是将一些讯息显示在这个Bar上面,在档案总管中就是在档案总管画面的最下方。范例12-6 StatusBar基本应用void _fastcall TForm1:Button1Click(TObject*Sender)StatusBar1-SimpleText=你刚刚按下了Button1;/-void _fastcall TForm1:Button2Click(TObject*Sender)StatusBar1-Simp
17、leText=你刚刚按下了Button2;/-void _fastcall TForm1:Button3Click(TObject*Sender)StatusBar1-SimpleText=你刚刚按下了Button3;/-void _fastcall TForm1:Edit1Change(TObject*Sender)StatusBar1-SimpleText=你刚刚修改了Edit1;/-void _fastcall TForm1:Edit2Change(TObject*Sender)StatusBar1-SimpleText=你刚刚修改了Edit2;1912-1.档案总管的接口 状态列组件(
18、StatusBar)范例12-7:StatusBar进阶应用 使用一个按钮、一个Edit、一个Image、以及一个StatusBar。在Status Bar上总共有四个字段,跟上一个范例不一样。在Status Bar上面按下鼠标右键,选择Panels Editor会出现StatusBar的Panel编辑画面。2012-1.档案总管的接口 状态列组件(StatusBar)范例12-7:程序代码(Part I)void _fastcall TForm1:Button1MouseDown(TObject*Sender,TMouseButton Button,TShiftState Shift,int
19、 X,int Y)StatusBar1-Panels-Items0-Text=你按下了Button 1;/-void _fastcall TForm1:Button1MouseUp(TObject*Sender,TMouseButton Button,TShiftState Shift,int X,int Y)StatusBar1-Panels-Items0-Text=你没按下Button 1;/-void _fastcall TForm1:Edit1Change(TObject*Sender)StatusBar1-Panels-Items1-Text=Edit1的文字是:+Edit1-Tex
20、t;/-void _fastcall TForm1:FormDragDrop(TObject*Sender,TObject*Source,int X,int Y)/设定Form上的DragDrop的Function,主要是用来让Image在Form上可以做Drag的动作TImage*buf=(TImage*)Source;buf-Left=X;buf-Top=Y;2112-1.档案总管的接口 状态列组件(StatusBar)范例12-7:程序代码(Part II)void _fastcall TForm1:FormDragOver(TObject*Sender,TObject*Source,i
21、nt X,int Y,TDragState State,bool&Accept)Accept=true;/让Form可以被允许DragOver/-void _fastcall TForm1:Image1StartDrag(TObject*Sender,TDragObject*&DragObject)StatusBar1-Panels-Items2-Text=正在拉图片;/当启动Drag的时候显示正在拉图片/-void _fastcall TForm1:Image1EndDrag(TObject*Sender,TObject*Target,int X,int Y)StatusBar1-Panel
22、s-Items2-Text=没在拉图片;/结束Drag的时候显示没在拉图片/-void _fastcall TForm1:FormMouseMove(TObject*Sender,TShiftState Shift,int X,int Y)/利用Form上面的MouseMove事件抓取鼠标光标,并且在StatusBar上将光标显示出来AnsiString Buf;Buf=(+IntToStr(X)+,+IntToStr(Y)+);StatusBar1-Panels-Items3-Text=鼠标光标(X,Y):+Buf;2212-1.档案总管的接口 状态列组件(StatusBar)范例12-7
23、执行结果2312-2.标头控制组件 标头控制组件所提供的功能,一般来说我们都会直接利用ListView来完成,而不是单纯的去拉一个标头控制组件下来用。因为HeaderControl一般都是用来区分是不是同类型的资料,例如在ListView中我们显示档案的话,文件名就会集体放在档名那一个Column,档案大小也都会放在同一个Column等,所以才会说大部分的使用都是利用ListView来完成。但是如果想要在Header部分加上一些图片等花俏的功能,还是得使用HeaderControl2412-3.进度状态显示组件 我们在安装应用程序(或是使用一些应用程序)的过程中,常常会有一条光棒跑出来告诉我们
24、目前工作正进行了多少百分比,这个组件我们称做进度状态列组件。进度状态列组件可以给使用程序的使用者非常高层次的讯息(可以马上了解现在的情况),也可以让使用者预估时间,也可以增加整个程序User Friendly的程度。在Borland C+Builder 6中,有ProgressBar、Cgauge这两个组件可以用来表示目前的完成度为何,其中ProgressBar位在Win32的页面中,而Cgauge在Sample这一页里。2512-3.进度状态显示组件 范例12-9:ProgressBar&CGauge操作实例 ProgressBar重要属性说明属性属性说明说明MaxProgress Bar跑
25、到100%时的那个值。MinProgress Bar在0%时的那个值。Orientation有Horizontal和Vertical两种不同的属性值,主要是用来决定Progress Bar是要往右增加或是往上增加。Position决定目前Progress Bar的光棒的所在位置。Smooth决定移动的光棒要用平滑的模式或是一格一格的模式呈现出来。2612-3.进度状态显示组件 范例12-9:ProgressBar&CGauge操作实例 CGauge重要属性说明属性属性说明说明BackColorCGauge在显示Progress Bar的地方的颜色Color除了Progress Bar的地方的颜
26、色。如果Progress Bar 不是标准的长条状,就有可能会需要用到Color这个属性。ForeColorProgress Bar本身的颜色。KindCGauge的表示种类,有HorizontalBar、Needle、Pie、Text、以及VerticalBar这五种不同的表示方法。MaxValueProgress Bar跑到100%时的那个值。MinValueProgress Bar在0%时的那个值。Progress决定目前Progress Bar的光棒的所在位置。跟ProgressBar这个组件的Position属性功能一样。ShowText决定是否要在Progress Bar上面显示出
27、目前完成的百分比数字。2712-3.进度状态显示组件 范例12-9:ProgressBar&CGauge操作实例 执行结果2812-3.进度状态显示组件 不管在执行ProgressBar或是CGauge的时候,整个程序几乎都陷入了停顿状态,也就是停止响应反过来说,当我们需要使用到ProgressBar或是CGauge的功能时,通常也是因为正在跑一个非常大的循环。现在有一个问题产生了,不管是在跑一个非常大的循环(CPU使用率100%)或是跑Progress的组件,都会让程序停止响应,这时候该怎么办?我们在这边将提出一个简单的解决方案 ApplicationProcessMessages()这个函
28、式,这个函式可以让我们的接口程序在执行中取得一些CPU Time,也因为这样,我们的接口就不会再发生没有响应的情况了。2912-3.进度状态显示组件 大家在写过几个程序之后,一定也会发现ProcessMessages()这个函式会有无效的时候,其实不是无效,而是刚刚好ProcessMessages()运作原理刚好跟你程序的做法无法match,这时候又该怎么办呢?在这边非常建议各位采用Thread的做法,虽然有些情况下不加入ProcessMessages()也可以正常运作,虽然有时候加入了ProcessMessages()就可以正常运作,但是最终的解决方法仍然是使用Thread的做法,因为Thr
29、ead才是真正将所有的工作分成执行绪后才交给CPU去执行,所以不管现在程序在跑什么东西,只要有开Thread,不管同时间有多少程序在跑一定都可以使用到CPU Time。关于Thread的介绍与使用,我们将在后面章节提到。3012-3.进度状态显示组件 其实除了上面介绍的这两个组件以外,还有其它很多组件都可以用来表示类似这方面的功能,例如曲线图、圆饼图、Shape,或是任何一个可以显示图形或是文字的都可以,只是需要程序设计师自己设计表现的模式。3112-4.轨迹追踪列 轨迹追踪列通常都是为了让使用者可以有比较方便的方法设定数值。例如在写一个骰子的程序时(一次丢多个骰子),我们一定要输入各点数会出
30、现的机率,这时候我们就可以利用TrackBar这个组件,采用拉的方式来设定好各点数出现的机率。概观的说,凡是需要设定数值时,都可以利用TrackBar来完成,这样可以增加不少User Friendly的效果喔!3212-4.轨迹追踪列 范例12-10:TrackBar操作实例 TrackBar重要属性说明属性属性说明说明Frequency在TrackBar上的标记多少单位划一格LineSize当你使用方向键控制TrackBar上面的指标时,按一下会移动多少格MaxTrackBar的最大值MinTrackBar的最小值Orientation有Horizontal和Vertical两种不同的属性值
31、,主要是用来决定TrackBar是要往右移动或是往上移动PageSize跟LineSize很像,不过LineSize是控制方向键对于TrackBar的移动数量,而PageSize是控制PageDown、PageUp对于TrackBar的移动数量Position目前TrackBar指针的位置SelEnd会显示出一个Range的光棒在TrackBar上,这个光棒的结束位置就是在SelEnd这个位置。SelStart会显示出一个Range的光棒在TrackBar上,这个光棒的结束位置就是在SelStart这个位置。一般来说SelStart的位置都设定在0,而SelEnd的位置跟Position的值是
32、同步的。因为这样就会将TrackBar已经被指针拉过的位置用其它颜色来表示SliderVisible决定指标要不要出现在TrackBar上ThumbLengthTrackBar的长度TickMarks决定标记点要在哪个方向TickStyle决定标记点产生的方式,Auto、Manual、或是None3312-4.轨迹追踪列 范例12-10 程序代码void _fastcall TForm1:TrackBar1Change(TObject*Sender)Label1-Caption=目前位置:+IntToStr(TrackBar1-Position);Label2-Caption=百分比率:+Fl
33、oatToStr(float)100*(float)TrackBar1-Position/(float)TrackBar1-Max)+%;3412-5.上下控制组件 上下控制组件跟TrackBar非常的类似,都是用来设定(表现)数值,只是TrackBar一定是一个调整棒在那边让使用者拉,但是上下控制组件就不一样了,你可以结合各种不同的VCL组件,例如可以跟Label或是Edit结合等等。在范例12-11中,我们将列出一些比较常跟上下控制组件结合的使用范例,也会提到CspinEdit这个类似上下控制组件。3512-5.上下控制组件 范例12-11:UpDown&CSpinEdit操作范例 UpD
34、own常用的属性说明属性属性说明说明AlignButton设定UpDown按钮的方向要在那个方向ArrowKeys决定我们是不是可以使用方向键来控制UpDown组件Associate想要跟UpDown组件结合的VCL组件Increment每次按一次按钮所增加或是减少的值MaxUpDown中会出现的最大的值,也就是Position这个属性的值不可以超过这个值MinUpDown中会出现的最小的值,也就是Position这个属性的值不可以小于这个值Orientation有Horizontal和Vertical两种不同的属性值,主要是用来决定UpDown的按钮是要上下方向或是左右方向Position目
35、前UpDown所在的位置(显示出来的值)Thousands如果数值超过1000的时候,需要需要每三个数字打一个逗点3612-5.上下控制组件 范例12-11:UpDown&CSpinEdit操作范例 CspinEdit常用的属性说明属性属性说明说明AutoSelect当CspinEdit刚好在focus的时候,Text中的值会自动被选取EditorEnabled设定我们可不可以直接Editor CspinEdit的TextIncrement每次按一次按钮所增加或是减少的值MaxValueCSpinEdit中会出现的最大的值,也就是Value这个属性的值不可以超过这个值MinValueCSpin
36、Edit中会出现的最大的值,也就是Value这个属性的值不可以低于这个值Value目前CSpinEdit所在的位置(显示出来的值)3712-5.上下控制组件 范例12-11:UpDown&CSpinEdit操作范例 程序代码 执行结果void _fastcall TForm1:UpDown3Click(TObject*Sender,TUDBtnType Button)if(Button=btPrev)ProgressBar1-Position-;elseProgressBar1-Position+;3812-6.日期时间 在BCB内有不少跟日期时间相关的组件可以用,例如Win32页次中的Dat
37、eTimePicker及MonthCalendar,System页次中的Timer,以及Sample页次中的Ccalendar这几个组件。范例12-12我们将实做这几个组件让大家看看。3912-6.日期时间 范例12-12 Timer Timer用白话一点的话来说就是定时器。也就是说我们可以利用Timer来做固定时间的定时器。除了可以利用Timer做时间的定时器外,在BCB中也有提供一些函式可以做时间的计算,例如时间间距的计算或是目前时间的回报等等。在范例程序12-12中,我们将上面我们所说的三个功能写出来当作范例,让大家可以对Timer这个组件以及有关DateTime方面的函式更熟悉。401
38、2-6.日期时间 范例12-12 月历 MonthCalendar&DateTimePicker&CCalendar MonthCalendar重要属性说明属性属性说明说明CalColor设定月历中的各种颜色Date月历中被选取的日期FirstDayOfWeek设定每个星期的第一天是星期几MultiSelect可以选多个日期ShowToday在月历上显示出今天的日期ShowTodayCircle在今天的日期上会出现一个圈圈包住WeekNumbers出现这一周是今年的第几周的数字4112-6.日期时间 范例12-12 月历 CCalendar重要属性说明属性属性说明说明Day目前选定的日子Gri
39、dLineWidth表格网格线的宽度Month目前选定的月份StartOfWeek设定每个星期的第一天是星期几UseCurrentDate预设为目前的日期Year目前表格显示出来的日期的年份4212-6.日期时间 范例12-12 Timer执行画面&DateTime执行画面4312-7.热键组件的使(HotKey)热键的使用在Windows系统中也是蛮重要的功能。虽然说目前大家都习惯使用鼠标,但是如果想让自己在使用软件上能加快速度或是提升效率,热键的使用及建立就相当的重要了。例如在Word中,你要打个顿号可能得从插入符号这个选单中慢慢找,但是如果你将他设定成快速键,节省下来的时间可能高达30秒
40、钟。4412-7.热键组件的使(HotKey)范例12-13:HotKey实作技巧 在BCB中有提供热键的组件。在范例12-13中我们将会设计一个范例程序来展现热键的实作技巧,以及使用热键的好处。在范例12-13中我们利用MainMenu这个组件当作我们要指定快速键的组件。设定好了之后按下快速键就会启动相关的函式。4512-7.热键组件的使(HotKey)范例12-13:HotKey实作技巧相关程序代码void _fastcall TForm1:BitBtn1Click(TObject*Sender)AnsiString StrBuf,HotKeyBuf;TMenuItem*ItemBuf;i
41、f(RadioGroup1-ItemIndex!=-1)StrBuf=RadioGroup1-Items-StringsRadioGroup1-ItemIndex;for(int i=0;i Items-Count;i+)if(ItemBuf=MainMenu1-Items-Itemsi-Find(StrBuf)!=NULL)break;if(ItemBuf)ItemBuf-ShortCut=HotKey1-HotKey;/-void _fastcall TForm1:ShowHotKeySet(TObject*Sender)ShowMessage(Set HotKey Success!n);
42、4612-7.热键组件的使(HotKey)范例12-13:HotKey实作技巧 执行画面4712-8.常驻在System Tray的程序 有很多软件常常会将自己的软件最小化在右下角的系统列,例如防毒软件或是一些常驻程序都会在系统列。在BCB中也有这样的组件提供给programmer使用,这个组件就是TrayIcon。范例12-14:系统列程序实作技巧 TrayIcon的使用方法非常的简单,在范例12-14中,我们除了放入一个TrayIcon外,我们也加入一个PopupMenu当做快速选单,也加入一个ImageList,并且放入多个Image在ImageList中,让TrayIcon最小化的时候
43、可以在系统列出现我们所设定的图示。4812-8.常驻在System Tray的程序 范例12-14:系统列程序实作技巧 主要程序代码void _fastcall TForm1:N1Click(TObject*Sender)/放置于系统列if(TrayIcon1-Visible=false)N1-Enabled=false;N2-Enabled=true;TrayIcon1-Visible=true;TrayIcon1-Minimize();void _fastcall TForm1:N2Click(TObject*Sender)/放置于桌面if(TrayIcon1-Visible=true)N
44、1-Enabled=true;N2-Enabled=false;TrayIcon1-Visible=false;TrayIcon1-Restore();4912-8.常驻在System Tray的程序 范例12-14:系统列程序实作技巧 主要程序代码void _fastcall TForm1:CheckBox1Click(TObject*Sender)/设定要不要在系统列开启动态的效果if(CheckBox1-Checked)TrayIcon1-AnimateInterval=Edit1-Text.ToInt()*1000;TrayIcon1-Animate=true;elseTrayIcon
45、1-Animate=false;TrayIcon1-IconIndex=0;5012-8.常驻在System Tray的程序 范例12-14:系统列程序实作技巧 主要程序代码void _fastcall TForm1:Edit1Change(TObject*Sender)/设定动态效果的时间长短if(CheckBox1-Checked)TrayIcon1-AnimateInterval=Edit1-Text.ToInt()*1000;TrayIcon1-Animate=true;elseTrayIcon1-Animate=false;TrayIcon1-IconIndex=0;5112-8.常驻在System Tray的程序 范例12-14:系统列程序实作技巧 主要执行画面5212-8.常驻在System Tray的程序 其实要实做系统列的程序也不一定需要使用BCB提供的TrayIcon这个VCL组件,我们也可以直接利用Win32 API所提供的函式来完成这个功能,而且透过Win32 API的方式更能提供多样化的功能。53本章习题 利用Win32 API实做出可以将程序最小化至系统列的应用程序。除了MainMenu可以结合HotKey外,找出其它的组件搭配HotKey实做出应用程序。试着拉出类似档案总管的接口(不需要实做程序代码)。54