我们平时看到的很多软件(PhotoShopDMax)都会在启动画面中显示当前正在启动哪个模块并在模块加载失败时给予提示这样的好处是可以让比较专业的软件使用者知道当前软件加载了哪些模块或者在软件发生启动错误时让用户得以反馈是启动的哪个模块时发生了以及在长时间的软件启动过程中让用户知道软件还在工作避免用户对其失去信息 好了说了那么多废话就来看看我是怎么制作这样一个程序的由于本人平时基本上都用Delphi来开发所以以下代码也都是Delphi的但是基本框架有了相信要用其它语言实现也不会很难另外以下这些代码是我在过去的历次开发过程中组部提炼出来的虽然还无法达到不修改即使用的地步但是要修改的内容也不会很多 我的这个类叫做TAppLoader首先要做的是让它接管部分程序的初始化工作 将工程dpr文件中的启动代码写成这样 var GAppLoader:TAppLoader; begin ApplicationInitialize; GAppLoader:=TAppLoaderCreate(); try if GAppLoaderDoLoad() then begin ApplicationRun; end; finally GAppLoaderFree; end; end 可以看到所有的启动代码都在TAppLoaderDoLoad()函数中了如果这个函数失败则会返回false此时就跳过ApplicationRun();过程直接跳出程序 接下来来看一下这个类的定义 TAppLoader = class (TObject) private FSplashForm: TfrmSplash; FManagerList:TList; protected procedure InitializeManager(var AManager;AManagerClass:TCustomManagerClass); procedure OnAppLoading(ASender:TObject;AEvent:String;ADelay:Integer=); public constructor Create(); destructor Destroy(); override; function DoLoad: Boolean; end; 除了刚才说到的DoLoad()函数外还可以看到这么两个函数InitializeManager()和OnAppLoading() 在说明InitializeManager()函数前需要先介绍这么一个类 TCustomManagerClass = class of TCustomManager; TCustomManager = class(TObject) private FOnAppLoading:TAppLoadingEvent; protected procedure Initialize();virtual;abstract; procedure Finalize();virtual;abstract; procedure DoAppLoading(AEvent:String); property OnAppLoading:TAppLoadingEvent read FOnAppLoading write FOnAppLoading; public constructor Create();virtual; end; 在我的程序中将所有的全局的资源管理类都叫做TxxxManager而TCustomManager就定义了这些类的一些基本行为说道这里可能还有必要解释一下什么是资源管理类说白了也就是将整个软件运行期需要经常访问的资源使用的功能都集中起来管理比如我将数据库连接叫做TDataManager将串口通讯功能类叫做TCommManager等等 这个基类定义了Initialize()和Finalize()两个虚方法是用来让TAppLoader启动或关闭服务用的这两个方法不同与构造与析构函数它们初始化的不是类本身的资源而是一些外部连接资源(比如网络连接文件句柄串口端口等等)它们可以允许在不销毁对象的前提下进行重新连接也就是说除了在TAppLoader中会调用Initialize()和Finalize()方法你也可以在软件的使用过程中调用这两个方法(比如用户选择了新的串口端口号) 接着可以看到TCustomManager中有一个OnAppLoading事件在Initialize()的过程中实际的Manager类就可以调用该方法在启动画面上显示文字了该事件实际会调用 TAppLoaderOnAppLoading()方法它的代码如下 procedure TAppLoaderOnAppLoading(ASender:TObject;AEvent:String; ADelay:Integer); begin if Assigned(FSplashForm) then begin if Assigned(ASender) then begin FSplashFormlblCaption:=ASenderClassName+: +AEvent; end else begin FSplashFormlblCaption:=AEvent; end; FSplashFormUpdate; if ADelay> then Sleep(ADelay); end; end; 其中FSplashForm就是启动画面了在TAppLoaderDoLoad()中调用各个Manager的Initialize()方法时这些Manager会根据自身当前初始化的内容回调这个OnAppLoading()函数此时就可以在启动画面上显示文字了 实际的Manager类中只要调用DoAppLoading()方法就可以将文字显示到启动画面上了如 procedure TFileImageManagerInitialize(); var Directory:String; FindHandle:THandle; FindFileData:TWinFindData; begin Directory:=ExtractFilePath(ParamStr())+decoders\; FindHandle:=FindFirstFile(PChar(Directory+*dcd)FindFileData); if FindHandle = INVALID_HANDLE_VALUE then exit; repeat if (FindFileDatadwFileAttributes and FILE_ATTRIBUTE_DIRECTORY)<>FILE_ATTRIBUTE_DIRECTORY then begin DoAppLoading(Loading + FindFileDatacFileName); AddDecoder(Directory+FindFileDatacFileName); end; until not FindNextFile(FindHandleFindFileData); WindowsFindClose(FindHandle); end; TAppLoader中还有这么一个函数 procedure TAppLoaderInitializeManager(var AManager;AManagerClass:TCustomManagerClass); var Instance: TCustomManager; begin Instance := TCustomManager(AManagerClassNewInstance); TCustomManager(AManager) := Instance; try InstanceCreate(); FManagerListAdd(@AManager); InstanceOnAppLoading:=OnAppLoading; InstanceInitialize(); InstanceOnAppLoading:=nil; except TCustomManager(AManager):= nil; raise; end; end; 它用来启动一个Manager并将其加入TAppLoader的一个FManagerList列表中在TAppLoader析构时它会自动按照这个列表来释放所有的Manager 在Manager的Initialize()结束后比较保险的是将它的OnAppLoading重新设为空这样如果在程序运行过程中由其它功能来调用Manager的Initialize()时就不会再回调到显示启动文字的部分了 最后看一下DoLoad()函数 function TAppLoaderDoLoad: Boolean; begin Result:=false; ApplicationTitle:=Ultra Album; FSplashForm:=TfrmSplashCreate(nil); try try FSplashFormShow; OnAppLoading(nilStarting); Sleep(); InitializeManager(GOptionManagerTOptionManager); InitializeManager(GRdItemClassManagerTRdItemClassManager); InitializeManager(GImageManagerTFileImageManager); InitializeManager(GThemeManagerTFileThemeManager); InitializeManager(GMaskManagerTFileMaskManager); OnAppLoading(nilEnding); ApplicationCreateForm(TfrmMain frmMain); if ParamCount>= then begin //deal with the filename in the parameter FSplashFormHide; frmMainShow; frmMainDoOpenFile(ParamStr()); end; Result:=true; except on E:Exception do begin MessageBox(ApplicationHandlePChar(EClassName+:+#+#+EMessage) PChar(ApplicationTitle)MB_ICONERROR); end; end; finally FreeAndNil(FSplashForm); end; end; 这个函数是我的一个软件中的代码它首先构造并显示一个启动画面然后使用InitializeManager()分别初始化了个Manager类其中的GOptionManagerGRdItemClassManager都是全局对象在今后需要访问时都使用这个全局对象来进行访问这里我没有使用Singleton模式因为我觉得这几个对象都必须在程序主窗体创建前完全初始化而Singleton的设计思路是在对象第一次使用时才创建它的实例在我的这个使用中不需要这样的功能当然你也可以自己改造这些Manager类成为Singleton的改动代码不会很多 最后再将程序的主界面创建出来可以看到这个主界面的创建代码就是我们从dpr文件中删除的那行 |