Visual C++ 5.0编程经验(下)
实现操作过程提示对话框
在使用Windows 95进行文件拷贝或删除操作时,用户一定见到过那种具有飞行文件动画的操作过程提示对话框。这一功能的加入不仅使我们能够在操作过程中随时取消操作,而且也使文件拷贝或删除操作变得生动活泼。其实,在使用Visual C++进行应用程序设计时,我们也可以使用下述方法在适当位置加入自己的操作过程提示对话框,步骤如下。
1. 为每一个操作过程提示对话框创建一个对话框类。为叙述方便,我们只假设应用程序需要一个操作过程提示对话框并以“CModel”作为对应的对话框类的名字。
2. 使用Visual C++提供的资源编辑器编辑提示对话框,比如加入一些文字说明和动画等。
3. 在CModel类的头文件(Model.h)中,首先加入两个成员变量:
CWnd* m_pParent;
//指向调用该提示对话框的框架类(或对话框类), 即它的“父类”
int m_nID;//记录该提示对话框的ID号
其次再加入下面两个成员函数:
CModel(CWnd* pParent = NULL);
//舍弃原有的构造函数,或者把原函数修改成这种 无模式对话框的构造函数
BOOL Create();
//该函数将调用创建基类的Create()函数创建对话 框
4. 在Model.cpp文件中,加入相应函数的实现部分:
CModel::CModel(CWnd* pParent /*=NULL*/)
: CDialog(CModel::IDD, pParent)
{
m_pParent=pParent;
m_nID=CModel::IDD;
//{{AFX_DATA_INIT(CModel)
// NOTE: the ClassWizard will add member initialization here
//}}AFX_DATA_INIT
}
BOOL CModel::Create()
{
return CDialog::Create(m_nID,m_pParent);
}
5. 同时按下Ctrl和W键或直接单击工具条上的ClassWizard按钮,打开ClassWizard对话框。在类名(Class name)列表框中选择该提示对话框类,在Object IDs列表框中选择该类的类名后,在消息(Messages)列表框中选择PostNcDestroy消息并双击它,这时ClassWizard就会在该对话框类中加入一个PostNcDestroy()函数。该函数在对话框窗口消失后,由OnNcDestroy()函数调用。因此,可以在该函数中加入一些扫尾工作,例如数据传送、释放指针空间等。
void CModel::PostNcDestroy()
{
// TODO: Add your specialized code here and/or call the base class
delete this;
CDialog::PostNcDestroy();
}
6. 在要调用提示对话框类的头文件中,先包含(#include)CModel类的头文件,再声明一个指向CModel类的对象的指针,如m_Dlg,并在该类的构造函数中,加入“m_Dlg = NULL;”。然后,在打开和关闭提示对话框的函数中加入如下一段程序:
if (m_Dlg==NULL) {
//如果当前没有活动的提示对话框,就创建一个
m_Dlg = new CModel(this);
m_Dlg->Create();
GetDlgItem(IDC_EXPORT)->EnableWindow(FALSE);
}
else //否则就激活它
m_Dlg->SetActiveWindow();
另外,在要关闭提示对话框的地方加入如下语句:
m_Dlg->DestroyWindow();
m_Dlg=NULL;
至此,我们已经拥有了自己的过程操作提示对话框。不过,它还不具有动画和随时取消操作的功能,读者不妨尝试着加入这些功能。
应用进程对其他应用程序的调用
在我们设计的应用程序中,很可能会用到其他应用程序来完成某一特定功能。例如,当我们为了便于数据的传输而对诸多文件进行压缩和解压缩时,一种做法是我们自己设计一个这样的压缩/解压缩程序,然后以动态链接库(DLL)或者函数库的形式由主应用程序调用。但更方便而且高效的做法是利用这方面现有的优秀软件,如ARJ.EXE等,并以进程的形式调用它,再在适当时候关闭它。下面将以此为例,具体介绍后一种方法的实现过程。
1. 在需要调用ARJ.EXE进行压缩/解压缩的类中,创建一个成员函数,不妨称作CreateBat(),其作用是生成一个批处理文件。由该批处理文件调用ARJ.EXE,并给出具体压缩/解压缩参数。然后,利用MS-DOS的DIR命令生成一个临时文件,以作为压缩/解压缩工作完成的标志。
编者注:Createbat源代码发表http://www.computerworld.com.cn/98/skill/default.htm。下同。欢迎访问!
该函数执行后,将生成一个批处理文件,内容大致是:
ARJ A -V1440 压缩后文件的路径名+文件名 被压缩文件的路径名+文件名 -Y -JM
DIR >临时文件名
或者是:
ARJ E -V1440 被解压缩文件的路径名+文件名 解压缩后文件的路径名+文件名 -Y -JM
DIR >临时文件名
2. 在需要调用ARJ.EXE进行压缩/解压缩的类中,再创建一个成员函数,不妨称作RunBat(),其作用是创建和执行进程来运行上述所生成的批处理文件,并在适当时候撤消进程。
3. 同时按下Ctrl和W键或直接单击工具条上的ClassWizard按钮,打开ClassWizard对话框。在类名(Class name)列表框中选择需要调用ARJ.EXE进行压缩/解压缩的类,在Object IDs列表框中选择该类的类名,在消息(Messages)列表框中选择WM_TIMER消息并双击它,这时ClassWizard就会在该类中加入一个OnTimer()函数。该函数将以一定的时间间隔检查压缩/解压缩程序是否已经执行完毕,即检查作为标志的临时文件是否已经存在,并及时修改状态变量“Search”,以便通知RunBat()函数结束进程。
void CMyCompress::OnTimer(UINT nIDEvent)
{
// TODO: Add your message handler code here and/or call default
CFile file;
CFileException Error;
if (file.Open(ExitFlag,CFile::modeRead,&Error)) {
Search=FALSE;
file.Close();
}
}
得到并修改各驱动器信息
在设计与文件输入/输出有关的应用程序时,我们需要在输入/输出文件前,了解一下源驱动器或者目标驱动器的各项信息,比如是否有磁盘在软驱中、它是否已打开写保护、现有磁盘的容量等。遗憾的是,MFC类库中没有提供支持这些功能的类,所以我们只能通过Win32 提供的函数来完成我们的要求。下面,笔者根据自己的编程实践,通过几段程序,来说明如何利用Win32提供的函数实现对驱动器的操作。读者可以根据自己的需要,把介绍的函数稍加修改后,即可插入到自己设计的应用程序中去。
*S FindDriverInfo()函数的功能是搜索计算机中所有驱动器,选择出其中软盘驱动器的驱动器号,依次加入到一个下拉列表框中。
*S EmptyDiskSpace()函数主要负责清空指定驱动器中的磁盘,同时它还负责记录指定驱动器中磁盘的容量,并得到该磁盘的序列号。在该函数中,还将调用上文中的DeletTree()的PreRemoveDirectory()函数,来完成清空工作。
*S 在MS-DOS和Windows95中,磁盘卷标最多由11个字符组成,并且字母的大小写不加区分。当需要设定指定驱动器中磁盘的卷标时,只要调用Win32的SetVolumeLabel()函数即可,在第一个参数中指明磁盘所在的驱动器号,在第二个参数中指明新的卷标号,例如:SetVolumeLabel(DriverNum, NewVolumeLabel)。
自编删除目录及其下属文件的函数
高版本的MS-DOS和Windows 95都提供了一个可以删除一个或多个目录及其下属文件和目录的命令,即DeleteTree命令。然而,无论在MFC类库还是在Win32函数库中,都没有相应的函数。这样,当我们在自己设计的应用程序中需要用到DeleteTree的功能时,自然想到的方法是通过进程调用或者系统调用的方式(如上文所述)调用MD-DOS或Windows 95下的DeleteTree命令。但实际上,Win32函数库已经为我们提供了其它的用于文件和目录操作的函数,利用它们不难设计出自己的DeleteTree()函数。
读者也许会感到有些疑惑,为什么前文强调进程调用优于自我设计的函数,而这里又反了过来?是的,在通常情况下,调用应用程序内部的函数比使用进程或者调用外部函数更灵活并且可以提高执行效率,也便于修改,DeleteTree()就是这种情况。然而,像设计压缩/解压缩这样的函数工作量大、算法复杂,而且调试和维护也需要一定代价,于是这时候还是采用“拿来主义”为好。
本文给出笔者设计的DeleteTree()函数,仅供参考。