现代操作系统都有文件系统的概念,所以有时候程序需要用户自己指定文件。在命令行下用户可以将自己指定的文件以参数形式传递,在图形界面下用户可以采用交互选择方式。在Windows下,我们把它叫做打开文件对话框(Open File Dialog),是通用对话框的一种(通用对话框还包括了颜色选择对话框、页面设置对话框、打印对话框等等)。今天我们来实战WinX里对打开文件对话框和保存文件对话框的封装,我们暂且把他们二者统称为文件对话框。WinX共提供了两种文件对话框,包括单文件对话框和多文件对话框,让我们看看WinX的操作和API方式、MFC方式有什么不同。
我们实战的例子程序就是step008-openfiles,该例程包含两个工程:
-
API方式
API实现打开文件对话框主要通过一个结构(OPENFILENAME)和一个API(GetOpenFileName)实现,此外还有一些辅助函数。OPENFILENAME定义如下(为了方便说明有所修改):













































详细介绍请参阅MSDN。
API方式下,如果要显示打开文件对话框,就需要调用API函数GetOpenFileName,他的参数就是上面这个结构的指针;如果需要显示保存文件对话框,就需要调用API函数GetSaveFileName。二者原型如下:




用户关心的返回值也都通过参数传回,毕竟用户需要的还是通过显示对话框得到一个全路径和文件名。
不过OPENFILENAME结构的一堆成员都需要用户指定,对于只是一个简单的打开或保存文件对话框来说,也确实麻烦了一些。
-
MFC方式
MFC对于打开和保存文件对话框进行了封装,都包括在CFileDialog里面。MFC方式显示文件对话框,必须先构建CFileDialog对象,然后调用DoModal方法来显示对话框窗口。我们看看CFileDialog构造函数和DoModal函数原型:




可见MFC将指定给OPENFILENAME结构的参数都放在了CFileDialog的构造函数中,DoModal没有参数。
通过查看MFC源代码,发现OPENFILENAME是作为CFileDialog的公共成员变量实现的。MFC还提供了虚拟函数,通过重载虚拟函数可以改变CFileDialg的行为。
MFC的封装貌似简化了操作,如将打开文件对话框和保存文件对话框封装在一个类里面,似乎达到了界面一致。但MFC方式最大的缺点是并没有把用户和底层完全隔离开来,用户还需要了解OPENFILENAME结构的成员的含义和用法。一般来说,对于文件对话框,包括多文件对话框,无非是用户希望这种GUI交互方式获取用户的输入,获得用户选择的或者要保存的文件名和路径等。一些不常用的不应该成为用户掌握基本用法的障碍。
-
WINX方式
WinX的文件对话框定义在CommonDialogs.h文件中。WinX是将单文件对话框和多文件对话框分别定义的。我们先来看看其对单文件的定义:





























枚举界定了文件对话框类型(打开或保存),最终表现为不同的类,OpenFileDialog和SaveFileDialog。最有意思的是(个人感觉),WinX不像MFC那样将OPENFILENAME结构作为成员变量封装,而且只是派生自这个系统结构。其实二者对象在二进制结构上没有区别,但是类里面的具体写法WinX方式就简单了,不像MFC那样还要ofn.xxx的方式来引用,WinX直接引用OPENFILENAME成员名就可以了。
当然,上面这个对最终用户基本没什么作用。用户关心的是使用是不是简单。假设你需要一个单文件打开文件对话框,就像本实战分析的教程实例中一样,只需要以下代码就可以:





在winx::OpenFileDialog类的构造函数中指定文件过滤器(我想一般个人都有不同的过滤器),其他参数都按照常用的默认值,最后DoModal就可以了。
我们看看winx::OpenFileDialog类构造函数和DoModal函数的原型:


















初看起来和MFC相比,只是有些参数顺序和所在函数有变化而已,深层次上来讲,WinX将抽象和具体化分的更清了。构造函数里的参数都是抽象层次上的,他们都不依赖于文件对话框的类型(打开或保存)、父窗口、资源句柄,而这些具体层次上的参数都移到了DoModal里面,在对话框显示出来的前一刻指定。也就是说,你可以构造一个OpenFileDialog对象,然后将它以不同的形式显示出来,如改变父窗口,改变类型,改变资源句柄。
最后又将单一FileDialog模板定义进行分解成了三个类,这样设计的指导思想又是什么?我认为是这样,如果用户一开始对自己要使用什么对话框是清楚的(到底是打开文件对话框还是保存文件对话框),就可以直接选择自己需要的类,其他参数就可以全部采用默认的,使用简单。用户用的中间过程想改变一下对话框行为,还有机会进行修改,使用灵活。这个小问题,WinX为用户还是想得很多。
除此外还有对多文件对话框的封装,基本思想一致,有兴趣的朋友可以看看commondialogs.h的源码。
另人遗憾的是,WinX只对通用对话框中的文件对话框进行了封装。