在MFC项目中使用CFileDialog打开文件时,一般的使用场景是选择一个文件,今天我们做一个选择多个文件的实验,运行环境是VS2022。
实验目标:在基于对话框的MFC项目中,通过调用CFileDialog类对象,将选择到的多个文件的路径及文件名保存到一个CString数组中,并通过显示控件逐一显示出来。
实验具体步骤如下:
一、建立一个基于对话框的MFC项目
打开VS2022->创建新项目->MFC应用->下一步->项目名称填写:testMultiFile->创建->应用程序类型选择:基于对话框->完成(其余项目均按缺省)。
二、设置对话框界面
选择对话框界面,将对话框上自动生成的控件删去。接着:
-
拖入一个静态文本框置于对话框的左上部,将描述文字改为"选择多个文件实验"。
-
拖入一个按钮控件,放到对话框的右上方,描述文字改为"开始实验",ID改为IDC_TEST;后边我们将在给这个按钮添加的处理程序中完成选择、提取信息、存储文件路径及文件名等工作。
-
再拖入两个按钮控件,并列放到"开始试验"按钮的下方,将描述文字分别改为"▲"和"▼",并将ID分别改为IDC_UP与IDC_DOWN;这两个按钮的作用是在显示时移动显示的内容,具体实现过程在为它们添加的处理程序中进行。
-
拖入一个静态文本框,放在对话框的右下方,将描述文字改为"文件路径及文件名"。
-
拖入一个文本编辑框,放到"文件路径及文件名"的右侧,我们将使用它显示选择的内容,为此,给他添加一个变量m_Path。(添加步骤:右键文本编辑框->添加变量->在名称中写入m_Path->完成)
三、在testMultiFileDlg.h中声明几个变量
这几个变量以public方式声明,具体名称、作用见代码后边的注释。
cpp
#define fileNameNum 1024 //可以选择文件名(含路径,下同)个数的最大值
const DWORD fileNameMaxLen = MAX_PATH; //单个文件名最大长度(字符数)
const DWORD bufferSize = (fileNameNum * fileNameMaxLen) + 1;
//定义存储所有被选择文件名的缓冲区大小
CString fileNameStr[fileNameNum];// 定义接收解析后文件名的数组
int fNumber = 0; //用于记录一共选择了多少个文件名
int showNum = 0; //用于记录要显示的文件名序号
四、添加处理程序
- 给"开始实验"按钮添加处理程序
右键"开始实验" ->添加事件处理程序 ->类列表选择:CtestMutltiFileDlg,其余按缺省 ->确定;这样,在testMultiFileDlg.cpp中,会增加一个函数void CtestMultiFileDlg:: OnBnClickedTest(),在这个函数的TODO:行下面,我们要添加一些代码。这些代码的功能是利用CFileDialog类生成的对话框选择多个文件,并通过对CFileDialog对象中m_ofn结构体属性的设置,使其能够容纳多个文件的路径及文件名;最后将获得的文件路径及文件名保存到我们定义的数组中。具体代码如下:
cpp
// TODO: 在此添加控件通知处理程序代码
CFileDialog fileDlg(TRUE, NULL, NULL, OFN_HIDEREADONLY | //以打开方式定义CFileDialog对象
OFN_OVERWRITEPROMPT | OFN_ALLOWMULTISELECT |
OFN_EXPLORER, _T("文件(*.*)|*.*||"));
TCHAR* fileNamesBuffer = new TCHAR[bufferSize]; //将文件名缓冲区开辟在堆区
fileNamesBuffer[0] = NULL;//初始化缓冲区,将缓冲区第一个和最后一个字节置0
fileNamesBuffer[bufferSize - 1] = NULL;
fileDlg.m_ofn.lpstrFile = fileNamesBuffer; //lpstrFile指向文件名缓冲区的指针
fileDlg.m_ofn.nMaxFile = bufferSize; //指定lpstrFile缓冲的大小,以TCHARs为单位
/* m_ofn是一个OPENFILENAME型的结构体,它包含了文件对话框的和各种,对于打开的那个文件可以使用其默认值,但对于打开多个文件时,要重新设置它的储存空间 */
if (IDOK == fileDlg.DoModal()) //运行打开文件对话框
{
CString fName; //临时变量
POSITION pos = fileDlg.GetStartPosition();
//POSITION是一个数据类型,它代表了一个抽象的迭代位置,实际上是结构体__POSITION的指针
//GetStartPosition()获得第一个文件路径及文件名的位置
while (pos != NULL)
{
fName = fileDlg.GetNextPathName(pos);//得到下一个文件位置,同时返回当前文件名(含路径)
fileNameStr[fNumber] = fName;// 取得文件名
fNumber++; //累加选择文件的个数
}
}
delete[] fileNamesBuffer;//释放在堆区内存
m_Path.SetWindowTextW(fileNameStr[0]); //把选择的第一个文件名做缺省显示
- 给"▲"按钮添加处理程序
添加步骤同上,添加的程序名为CtestMultiFileDlg::OnBnClickedUp(),这个函数的作用简单,就是按动这个按钮时,按倒序依次显示旭泽的文件名。具体代码也是要加到TODO行下面:
cpp
// TODO: 在此添加控件通知处理程序代码
showNum--;
if (showNum <0)showNum = 0;
m_Path.SetWindowText(fileNameStr[showNum]);
- 给"▼"按钮添加处理程序
添加的程序名为CtestMultiFileDlg::OnBnClickedUp(),它的作用是按正序显示选择的文件名。代码如下:
cpp
// TODO: 在此添加控件通知处理程序代码
showNum++;
if (showNum == fNumber)showNum = fNumber-1;
m_Path.SetWindowText(fileNameStr[showNum]);
五、至此,这个实验就算结束,我们看一下运行效果:
