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

  首 页 | 新 闻 | 技术中心 | 第二书店 | 《程序员》 | 《开发高手》 | 社 区 | 黄 页 | 人 才
移 动专 题SUNIBM微 软微 创精 华Donews人 邮
我的技术中心 
我的分类我的文档
最新文章发表文章
专栏管理使用说明

 RSS 订阅 
Windows/.NET
.NET  (rss)    
Visual C++  (rss)    
Delphi  (rss)    
Visual Basic  (rss)    
ASP  (rss)    
JavaScript  (rss)    
Java/Linux
Java  (rss)    
Perl  (rss)    
综合
其他开发语言  (rss)    
文件格式  (rss)    
企业开发
游戏开发  (rss)    
网站制作技术  (rss)    
数据库
数据库开发  (rss)    
软件工程
其他  (rss)    

积极原创作者 
windoze (12)
ngnr (3)
unique001 (2)
duckur (2)
CanvasHat (5)
chensheng913 (132)
yolle (1)
sbf2000 (1)
ycg01 (1)
ezdevelop (29)
CSDN - 文档中心 - Delphi 阅读:195   评论: 0    参与评论
标题  组件制作之五(托盘组件)     linzhengqun [原作]
关键字  组件制作之五(托盘组件)
出处 

这将是最后一个组件了,目标定为非可视化,事实上非可视化组件要比可视化组件难做,因为是从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;

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;

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

      end;

      WM_LBUTTONUP:  //左单击弹起

      begin

        GetCursorPos(P);

        if IsClickIn then

        begin

          IsClickIn:=False;

          Click;

          if FRmode=LClick 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;

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

      end;

      WM_RBUTTONDOWN: //右单击下

      begin

        GetCursorPos(P);

        IsClickIn:=True;

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

      end;

      WM_RBUTTONUP: //右单击弹起

      begin

        GetCursorPos(P);

        if IsClickIn then

        begin

          IsClickIn:=False;

          Click;

          if FRmode=RClick 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;

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

       end;

      end;

  end

  else

     Msg.Result := DefWindowProc(FHandle, Msg.Msg, Msg.wParam, Msg.lParam);

end;

//以下为几个事件的调度函数,比较简单.

procedure TMyTray.DblClick;

begin

  if Assigned(FOnIconDblClick) then

    FOnIconDblClick(Self);

end;

 

procedure TMyTray.Click;

begin

  if Assigned(FOnIconClick) then

    FOnIconClick(Self);

end;

 

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

begin

  if Assigned(FOnIconMouseDown) then

    FOnIconMouseDown(Self, Button, Shift, X, Y);

end;

 

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

begin

  if Assigned(FOnIconMouseUp) then

    FOnIconMouseUp(Self, Button, Shift, X, Y);

end;

 

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

begin

  if Assigned(FOnIconMouseMove) then

    FOnIconMouseMove(Self, Shift, X, Y);

end;

 

end.

 

组制作完毕,相信经过上面的讲解,以及代码的注释,应该不难理解。接下来是什么呢,给我的托盘控件来点效果,即在设计器中,当双击该组件,或右击快捷菜单第一项时,会弹出一个About对话框,来说明我的托盘组件。

这个就要用到组件编辑器啦 。几本经典书中都有说及,比如Deplphi开发人员指南,我也是从那里学来的,不过却遇到了一些问题,折磨了几天才解决。

这里不想详细介绍,去看一下那些书,大概也就知道了,只略说一下。

其原理就是实现一个继承自TComponentEditor的子类TTrayIconEditor,并在其中覆盖以下三个方法:

function GetVerbCount: Integer; override;

function GetVerb(Index: Integer): string; override;

procedure ExecuteVerb(Index: Integer); override;

可以精略理解为:

GetVerbCount指定控件快捷菜单的项数

GetVerb指定快捷菜单中的相关项的名字

ExecuteVerb执行点击快捷菜单项后的动作

 

接着在Register方法中调用RegisterComponentEditor(TMyTray,TTrayIconEditor);

第一个参数为组件类名,第二个为组件编辑器的类名。

而上面的方法必须引用DesignIntf,DesignEditors

 

当我在我的组件单元这样做之后出现问题了,编译安装没有问题。我建立测试程序,并拉一个托盘组件,双击它,可以出现About对话框,右击菜单第一项也没有问题。可是当我运行测试程序时,却出现了这样的编译错误:

[Fatal Error] Unit1.pas(7): File not found: 'DesignEditors.dcu'

 

这让我痛苦了好几天,书上是这么说的,应该没有什么错误呀。后来经过摸索,才找到了解决之道。

解决的办法就是将组件编辑器类放在另一个单元中,并在这个单元引用我的托盘组件单元。

并安装之。这才可以正常运行,这个编辑器单元如下:

 

unit AboutTray;

 

interface

 

uses

  SysUtils,Classes,DesignIntf,DesignEditors,Forms,

  MyTray;

 

type

 TTrayIconEditor = class (TComponentEditor)

    function GetVerbCount: Integer; override;

    function GetVerb(Index: Integer): string; override;

    procedure ExecuteVerb(Index: Integer); override;

  end;

 

procedure Register;

 

implementation

 

///TTrayIconEditor

procedure TTrayIconEditor.ExecuteVerb(index:integer);

begin

 case index of

 0: application.MessageBox('你好,这是风做的托盘组件!!','关于');

 end;

end;

 

function TTrayIconEditor.GetVerb(index:integer):String;

begin

  case index of

    0:Result:='About MyTray';

  end;

end;

 

function TTrayIconEditor.GetVerbCount:integer;

begin

  Result:=1;

end;

 

 

procedure Register;

begin

  RegisterComponentEditor(TMyTray,TTrayIconEditor);

end;

 

end.

 

至此,托盘组件完毕,拉下它放在窗体设计器中,双击,弹出对话框

里面内容为:“你好,这是风做的托盘组件!!”。哈哈,你成功啦

 

 

做为组件制作的最后一个内容,我想用一个包来把我的所有组件单元包含起来,并放在我自己新建的一个面板中。

这样做之前,要把以前安装下去的组件删除。知道怎么样删除,如果不知道,请看我在第一篇中说的。

然后在打开所有的组件单元,把RegisterComponents(‘Samples', [TCoolMemo]);里面的

Samples改为Wind。然后保存

接着,在IDE中点File-》New-》Other…

弹出来的New Items对话框,选中New页面,并选中其中的Package

这里弹出一个新建的包编辑器。

先在IDE中点File-》Save。将包编辑器保存。保存在组件的单元所在的文件夹中

我的所有组件单元都放在Delphi7/MyCom文件夹中。因此这个包当然也保存在这里。

 

然后,点包编辑器上边的Add,将所有的组件单元加进去,当然也保括上面说的组件编辑器单元啦。

加进去后,点包编辑器上边的Compile,编译完毕,再点Insall

成功,看看面板。所有以前做过的组件全在Wind面板中了。

而这时候,我的任务也完毕了。

 

 

结语

 

这次的组件之旅终于走完了,也许有人会笑我浅薄,认为这么简单的东西,有必要拿出来么。也许是比较简单吧,但一定有人会需要的,相信我的文章会给他们帮助的。因为这些是我曾经学到的知道,遇到的问题并解决它。所以我个人觉得是很珍贵的。并且经过写这几篇,我把这些知识记得更牢了。这种利己利人的事,何乐而不为呀。

在此,谢谢大家的阅读,也许下次还有机会再见面,不过现在要说再见了。祝你们愉快。


相关文章
对该文的评论


网站简介 - 广告服务 - 网站地图 - 帮助信息 - 联系方式 - English
北京百联美达美数码科技有限公司 版权所有 京ICP证020026号
Copyright © CSDN.NET, Inc. All Rights Reserved
<script> document.write(" "); </script>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值