我们在Windows98环境下执行拷贝文件、查找文件或计算机等耗时比较长的操作时,Windows会显示一个小小的动画,指示正在进行的操作,与死板的静止图像相比增色不少。那么我们自己开发软件时,能否也显示一个这样的动画提示呢?我在开发一个外贸应用软件系统时,遇到的数据量很大,当通过复合条件查找时,因为不是数据库表的每个项目都有索引,所以很费时,系统也会表现出长时间停顿,用户感觉极为不爽。我经过一段时间的探索,开发了一个能够在采用的开发环境PowerBuilder下调用的动画DLL,由于采用多线程编程,PB调用的DLL函数能够及时将控制权交还为PB,不影响应用系统的运转。用户能够看到一个东西在动,也就不会想到系统是不是停止响应了,感觉时间也似乎没那么久了。
代码与编译选项
(1) 在C++Builder的File菜单下选择New,在New Item对话框的New属性中选择DLL,C++Builder就会创建一个空白的DLL项目。
(2) 在File菜单下选择New Form,C++Builder创建一个空白的Form,修改它的属性为
1 2 3 4 5 |
BorderStyle=bsDialog BorderIcons的子属性均为False FormStyle=fsStayOnTop Position= poScreenCenter Name=StatusForm |
(3) 在Form上添加一个Win32下的Animate控件Animate1,修改它的属性为
Align=alTop
(4) 在Form上添加一个Standard下的Button控件Button_Cancel,再添加System下的Timer控件Timer1,设置定时Interval时间位250,以较快的响应用户的取消请求。
因为PB应用系统与动画窗体代码分别属于两个线程,不能采用PB线程直接关闭动画窗体线程的窗口,否则会引起系统运行不正常,因此采用PB线程设置关闭标志,而动画线程采用Timer控件定时检查标志,一旦检测到关闭标志,就关闭窗口,清除线程标志,结束动画线程。
下面给出编码及编码原理:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 |
1.DLL DLL主体代码: /********************************** * DLL主体代码 * 定义DLL公用变量 * g_CommonAVI 对Animate控件动画类型索引 * gi_Canceled Button_Cancel按钮是否被选择过 * gi_AVIType 要显示的动画类型,由DLL输出函数做为参数输入 * gi_RequestClose 请求动画线程关闭标志 * gi_WindowActive 动画窗口所处的状态 * lpsWinTitle 动画窗体的标题,由DLL输出函数做为参数输入 */ TCommonAVI g_CommonAVI[]={ aviNone, aviFindFolder, aviFindFile, aviFindComputer, aviCopyFiles, aviCopyFile, aviRecycleFile, aviEmptyRecycle, aviDeleteFile }; int gi_Canceled=0,gi_AVIType=0; int gi_RequestClose=0,gi_WindowActive=0; char lpsWinTitle[256]; HWND hWndParent=NULL; /* 定义DLL 输出函数 */ extern "C" __declspec(dllexport) int pascal DllEntryPoint(HINSTANCE hinst, unsigned long reason, void*); extern "C" __declspec(dllexport) int pascal ShowStatusWindow(int AVIType, LPSTR WinTitle,long hWnd); extern "C" __declspec(dllexport) int pascal GetStatus(int ai_CloseWin); extern "C" __declspec(dllexport) int pascal CloseStatusWindow(); /*定义线程TformThread:*/ class TFormThread : public TThread{ public:// User declarations __fastcall TFormThread(bool CreateSuspended); void __fastcall Execute(void); }; __fastcall TFormThread:: TFormThread(bool CreateSuspended): TThread(CreateSuspended){ } /* 动画线程执行代码, 动画窗体的定时器控件会关闭它, 清除窗体存在标志后结束线程的运行 */ void __fastcall TFormThread::Execute(void){ gi_WindowActive=1; StatusForm=new TStatusForm(NULL); StatusForm- >Caption=lpsWinTitle; StatusForm- >ShowModal(); gi_WindowActive=0; delete StatusForm; gi_RequestClose=0; } /* 定义一个线程实例指针 */ TFormThread *FormThread; /********************************************** * 输出函数代码实现部分 * DllEntryPoint 32位DLL入口 * ShowStatusWindow 显示动画窗口, 它通过创建一个线程来创建窗口,避免由于窗口 的MODAL属性而使控制权不能及时的返还给调用者 * GetStatus 取得撊∠麛状态,即用户有没有选择撊∠麛按钮 * CloseStatusWindow 关闭动画窗口, */ __declspec(dllexport) int WINAPI DllEntryPoint (HINSTANCE hinst, unsigned long reason, void*) { return 1; } __declspec(dllexport) int pascal ShowStatusWindow(int AVIType,LPSTR WinTitle,long hWnd){ hWndParent=(HWND)hWnd; memset(lpsWinTitle,0,sizeof(lpsWinTitle)); strncpy(lpsWinTitle,WinTitle,sizeof(lpsWinTitle)-1); if (AVIType >0 && AVIType< =8) gi_AVIType=AVIType; FormThread=new TFormThread(true); FormThread- >Priority = tpNormal; FormThread- >Resume(); } __declspec(dllexport) int pascal GetStatus(int ai_CloseWin){ if (gi_Canceled) if (gi_WindowActive){ gi_RequestClose=1; while(gi_RequestClose); } return gi_Canceled; } __declspec(dllexport) int pascal CloseStatusWindow(){ if (gi_WindowActive){ gi_RequestClose=1; while(gi_RequestClose); } return gi_Canceled; } 2.窗体StatusForm的代码: TStatusForm *StatusForm; //----------------------------------- extern int gi_Canceled; extern int gi_AVIType; extern TCommonAVI g_CommonAVI[]; __fastcall TStatusForm:: TStatusForm(HWND ParentWindow) : TForm(ParentWindow) { gi_Canceled=0; } //----------------------------------- //取消按钮并不直接关闭窗体, 而指示设置取消标志,供调用者查看 void __fastcall TStatusForm:: Button_CancelClick(TObject *Sender) { gi_Canceled=1; // ModalResult=mrCancel; } //----------------------------------- // 激活动画,在FORMCREATE事件中 void __fastcall TStatusForm:: FormCreate(TObject *Sender) { Animate1- >CommonAVI=g_CommonAVI[gi_AVIType]; Animate1- >Active = true; } //----------------------------------- extern int gi_RequestClose; // 定时器事件检测到结束标志关闭窗体 void __fastcall TStatusForm:: Timer1Timer(TObject *Sender) { if (gi_RequestClose){ ModalResult=mrOk; } } //----------------------------------- |
(5) 设置编译选项:Project->Options打开Project Options对话框,清除Linker属性页中的Use Dynamic RTL标志,清除Packages属性页中的Build with runtime packages。这样只要单个DLL就可以运行了,而不必安装一些动态连接运行时间库。使用动画DLL
上面编译出DLL可以由其它任何开发语言调用,下面给出在PB中的使用方法。
(1) 定义:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
//Declare - > Global External Functions FUNCTION Long ShowStatusWindow(Long AVIType,String WinTitle,long hWnd) & LIBRARY "STATWIN.DLL" ALIAS FOR "ShowStatusWindow" FUNCTION Long GetCancelStatus(Long CloseWindow) & LIBRARY "STATWIN.DLL" ALIAS FOR "GetStatus" FUNCTION Long CloseStatusWindow() & LIBRARY "STATWIN.DLL" ALIAS FOR "CloseStatusWindow" (2) 调用: long ll_EndTime //显示查找文件夹动画 ShowStatusWindow(2) setpointer(HourGlass!) ll_EndTime = Cpu() + 10 * 1000 DO if GetCancelStatus(0)=1 then exit end if // 做想做的事情 LOOP UNTIL cpu() > ll_EndTime CloseStatusWindow() |