需要项目源码的可以私信作者~~~
项目概述
本项目旨在实现一个简单的资源管理器,用于模拟计算机操作系统中文件夹和文件的管理操作。该资源管理器实现基本的录入、修改、删除、输出和查询操作。此外,项目还包含一些扩展功能,如返回、导出、导入、排序等。
工具准备
Visual Studio 社区版 2022
注:需安装MFC扩展包!!!
项目创建
打开VS,新建项目,选择MFC应用
以实现图形化界面
应用程序类型选择基于对话框
,使用MFC处选择在静态库中使用MFC
后即可创建项目
项目编写
创建项目完成后,映入眼帘的就是我们的主界面
,可以在资源视图
–>Dialog
中打开
主界面设计
首先我们完成主界面
的图形设计
通过拖拽右侧工具箱的控件Edit Control
、Button
、List Control
通过右键控件选择属性
修改button
的描述文字
和List Control
的视图
这样,我们就完成主界面
的图形设计
文件浏览
弹出资源管理器
接着,我们右键List Control
选择添加变量
,为其命名变量m_FileList
然后我们回到解决方案资源管理器视图
,在项目
–>源文件
下找到项目名Dlg.cpp
的文件,其就是主界面
对应的主文件
在OnInitDialog
初始化函数下添加以下代码以设计List Control
的表头
m_FileList.SetExtendedStyle(LVS_EX_GRIDLINES | LVS_EX_FULLROWSELECT);
m_FileList.InsertColumn(0, L"名称", 0, 190);
m_FileList.InsertColumn(1, L"类型", 0, 80);
m_FileList.InsertColumn(2, L"目录", 0, 250);
m_FileList.InsertColumn(3, L"大小", 0, 100);
m_FileList.InsertColumn(4, L"时间", 0, 220);
效果如下:
然后我们回到主界面
,双击Button
控件进入点击事件函数的编写,实现弹出资源管理器
// 弹出文件管理器
void CResourcesManagementDlg::OnBnClickedButton1()
{
UpdateData(TRUE);
memset(wcPath, 0, MAX_PATH);
BROWSEINFO bi;
bi.hwndOwner = m_hWnd;
bi.pidlRoot = NULL;
bi.lpszTitle = L"选择目录";
bi.ulFlags = 0;
bi.lParam = 0;
bi.iImage = 0;
bi.lpfn = NULL;
bi.pszDisplayName = wcPath;
LPITEMIDLIST lp = SHBrowseForFolder(&bi);
SHGetPathFromIDList(lp, wcPath);
if (!wcscmp(wcPath, L""))
{
MessageBox(L"选择失败", L"错误", MB_OK);
return;
}
else
{
MessageBox(L"选择成功", L"提示", MB_OK);
m_DriPath.Format(L"%s", wcPath);
m_FileList.DeleteAllItems();
FindDirFile(wcPath);
}
UpdateData(FALSE);
}
导入目录
另外的,我们编写FindDirFile
函数实现导入目录
功能
注:文件夹大小为0
// 导入目录
void CResourcesManagementDlg::FindDirFile(WCHAR* wcDirPath)
{
WCHAR wcRootPath[1024];
WCHAR wcSubPath[1024];
WCHAR wstrFileSize[32];
WIN32_FIND_DATA wfdFileData = { 0 };
DWORD dwIndex = 0;
SYSTEMTIME fileTime;
wsprintf(wcRootPath, L"%s*.*", wcDirPath);
HANDLE hFile = FindFirstFile(wcRootPath, &wfdFileData);
if (hFile != INVALID_HANDLE_VALUE)
{
do {
memset(wcSubPath, 0, 1024);
if ('.' == wfdFileData.cFileName[0])
{
continue;
}
wsprintf(wcSubPath, L"%s%s", wcDirPath, wfdFileData.cFileName);
if (wfdFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
m_FileList.InsertItem(dwIndex, wfdFileData.cFileName, dwIndex);
m_FileList.SetItemText(dwIndex, 1, L"目录");
m_FileList.SetItemText(dwIndex, 2, wcSubPath);
m_FileList.SetItemText(dwIndex, 3, L""); // 目录没有大小
FileTimeToSystemTime(&(wfdFileData.ftLastWriteTime), &fileTime);
m_FileList.SetItemText(dwIndex, 4, ConvertSystemTimeToWString(fileTime).c_str()); // wfdFileData.ftLastWriteTime
}
else
{
m_FileList.InsertItem(dwIndex, wfdFileData.cFileName);
m_FileList.SetItemText(dwIndex, 1, L"文件");
m_FileList.SetItemText(dwIndex, 2, wcSubPath);
// 文件大小
ULARGE_INTEGER fileSize;
fileSize.LowPart = wfdFileData.nFileSizeLow;
fileSize.HighPart = wfdFileData.nFileSizeHigh;
_ultot_s(fileSize.QuadPart, wstrFileSize, 10, 10); // 转换为字符串,不包括逗号分隔符
m_FileList.SetItemText(dwIndex, 3, wstrFileSize);
// 文件最后修改时间
FileTimeToSystemTime(&(wfdFileData.ftLastWriteTime), &fileTime);
m_FileList.SetItemText(dwIndex, 4, ConvertSystemTimeToWString(fileTime).c_str());
}
dwIndex++;
} while (FindNextFile(hFile, &wfdFileData));
}
}
此外我们还要实现辅助函数ConvertSystemTimeToWString
实现SystemTime
类型转WString
类型,帮助查询文件最后修改时间
// SystemTime类型 转 WString类型
std::wstring ConvertSystemTimeToWString(const SYSTEMTIME& st)
{
// 足够大的缓冲区来存储日期和时间字符串
wchar_t buffer[128];
// 使用swprintf_s或swprintf来格式化日期和时间
#ifdef _MSC_VER // 检查是否是Microsoft编译器
swprintf_s(buffer, sizeof(buffer) / sizeof(wchar_t), L"%04d-%02d-%02d %02d:%02d:%02d",
st.wYear, st.wMonth, st.wDay,
st.wHour, st.wMinute, st.wSecond);
#else
swprintf(buffer, sizeof(buffer) / sizeof(wchar_t), L"%04d-%02d-%02d %02d:%02d:%02d",
st.wYear, st.wMonth, st.wDay,
st.wHour, st.wMinute, st.wSecond);
#endif
// 将C风格的字符串转换为std::wstring
return std::wstring(buffer);
}
升降序
需要我们在主菜单
中为List Control
添加类向导
消息
处选择LVN_COLUMNCLICK
我们对主菜单
中新生成的OnColumnclickList1
函数进行编写,如下:
// 根据内容升降序
void CResourcesManagementDlg::OnColumnclickList1(NMHDR* pNMHDR, LRESULT* pResult)
{
// 将NMHDR指针转换为LPNMLISTVIEW指针
LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);
// 初始化结果变量
*pResult = 0;
// 如果当前点击的列ID与上一次点击的列ID不同
if (dwSelColID != pNMLV->iSubItem)
{
// 更新选中的列ID
dwSelColID = pNMLV->iSubItem;
bASC = bASC;
}
else
// 如果点击的是同一列,则切换升序/降序
bASC = !bASC;
// 获取ListView中的项数
int count = m_FileList.GetItemCount();
// 为List中的每一项设置项数据
for (int i = 0; i < count; i++)
m_FileList.SetItemData(i, i);
// 对List进行排序
m_FileList.SortItems(CompareFunc, (LPARAM)(&m_FileList));
// 初始化结果变量
*pResult = 0;
}
弹出菜单
回到资源视图
,我们可以右键项目,选择添加资源
–>Menu
,新建菜单
我们对菜单
进行简单设计
回到主界面
,我们选中对话框,右键选择类向导
在消息框选择NM_RCLICK
完成后,主文件会生成OnRclickList1
函数
我们通过以下代码实现弹出菜单功能
// 弹出菜单
void CResourcesManagementDlg::OnRclickList1(NMHDR* pNMHDR, LRESULT* pResult)
{
LPNMITEMACTIVATE pNMItemActivate = reinterpret_cast<LPNMITEMACTIVATE>(pNMHDR);
dwIndexFlag = pNMItemActivate->iItem;
POINT pt = {};
GetCursorPos(&pt);
HMENU hMenu = LoadMenu(AfxGetApp()->m_hInstance, MAKEINTRESOURCE(IDR_MENU1));
hMenu = GetSubMenu(hMenu, 0);
TrackPopupMenu(hMenu, TPM_CENTERALIGN, pt.x, pt.y, 0, m_hWnd, NULL);
*pResult = 0;
}
我们还需要编写回调函数CompareFunc
帮助升降序功能的实现
// 添加回调函数
static int CALLBACK CompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
{
// 将 lParamSort 转换为 CListCtrl 指针,以便后续使用列表控件的方法
CListCtrl* pListCtrl = (CListCtrl*)lParamSort;
// 定义一个 LVFINDINFO 结构体,用于查找列表项
LVFINDINFO findInfo;
findInfo.flags = LVFI_PARAM; // 指示按 lParam 查找
findInfo.lParam = lParam1; // 第一个列表项的参数值
// 查找 lParam1 对应的列表项索引
int iItem1 = pListCtrl->FindItem(&findInfo, -1);
// 更新 findInfo 的 lParam 为 lParam2,并查找 lParam2 对应的列表项索引
findInfo.lParam = lParam2;
int iItem2 = pListCtrl->FindItem(&findInfo, -1);
// 获取两个列表项在指定列的文本内容
CString strItem1 = pListCtrl->GetItemText(iItem1, dwSelColID);
CString strItem2 = pListCtrl->GetItemText(iItem2, dwSelColID);
char* str1 = (char*)strItem1.GetBuffer(strItem1.GetLength());
char* str2 = (char*)strItem2.GetBuffer(strItem1.GetLength());
// 根据 bASC 变量的值决定是升序比较还是降序比较
if (bASC)
// 升序比较
return strcmp(str1, str2);
else
// 降序比较
return strcmp(str2, str1);
}
打开目录
回到菜单视图
我们右键刚刚添加的打开目录
选择添加事件处理程序
,类列表
这里我们还是选择刚刚的主文件
之后我们对主文件
新生成的函数进行编写,实现打开目录
功能
// 打开目录
void CResourcesManagementDlg::On32771()
{
UpdateData(TRUE);
// 文件路径
CString csDirPath = m_FileList.GetItemText(dwIndexFlag, 2);
// 文件类型
CString csDirType = m_FileList.GetItemText(dwIndexFlag, 1);
if (csDirType == L"文件")
{
MessageBox(L"该路径不是目录", L"错误", MB_OK);
return;
}
// 拼接路径
csDirPath = csDirPath + L"\\";
WCHAR wcDirPath[1024];
memset(wcDirPath, 0, 1024);
CStringW strW = CT2CW(csDirPath);
wcscpy(wcDirPath, strW);
// 刷新目录
m_FileList.DeleteAllItems();
FindDirFile(wcDirPath);
UpdateData(FALSE);
}
文本模式打开文件
同样的,我们可以菜单视图
添加文本模式打开文件
行,并添加对应的事件处理程序
// 文本模式打开文件
void CResourcesManagementDlg::On32774()
{
UpdateData(TRUE);
// 当前文件类型
CString csDirType = m_FileList.GetItemText(dwIndexFlag, 1);
// 提示
if (csDirType == L"文件")
{
CString csFilePath = m_FileList.GetItemText(dwIndexFlag, 2);
// 打开文本文件
ShellExecute(NULL, L"open", csFilePath, NULL, NULL, SW_SHOWNORMAL);
}
else
{
MessageBox(L"无法打开目录", L"提示", MB_OK);
}
UpdateData(FALSE);
}
刷新列表
我们还可以为添加一个刷新目录
功能
// 刷新目录
void CResourcesManagementDlg::On32772()
{
// 清除并重新填充列表控件
m_FileList.DeleteAllItems();
// 刷新目录
FindDirFile(wcPath);
}
返回上一级文件夹
我们还可以为程序编写返回上一级文件夹
功能
// 返回上一级文件夹
void CResourcesManagementDlg::On32777()
{
g_DirFilePath = m_FileList.GetItemText(dwIndexFlag, 2);
// 尝试找到最后一个路径分隔符并删除其后的所有内容
int pos = g_DirFilePath.ReverseFind('\\');
if (pos != -1)
{
g_DirFilePath = g_DirFilePath.Left(pos); // 截取到最后一个路径分隔符之前的内容
}
else
{
// 处理根目录或无效路径的情况
MessageBox(L"已经是根目录或无效路径", L"提示", MB_OK);
return;
}
// 清除并重新填充列表控件
m_FileList.DeleteAllItems();
// 刷新目录
FindDirFile(wcPath);
}
这样,我们就完成了文件浏览板块
文件管理
新建文件
首先我们在资源视图
下新建一个Dialog
作为新建文件
的窗口
效果如下:
之后,我们为对话框添加CreateFile
类,为编辑框添加变量m_FileName
再为Button
控件添加创建文件
功能,代码如下:
// 新建文件
void CRkCreateFile::OnBnClickedButton1()
{
UpdateData(TRUE);
if (m_FileName == L"")
{
MessageBox(L"无文件名", L"提示", MB_OK);
return;
}
else
{
CString TempPath;
TempPath = g_DirFilePath + L"\\" + m_FileName;
HANDLE hFile = CreateFileW(TempPath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
MessageBox(L"创建失败", L"错误", MB_OK);
OnOK();
return;
}
else
{
MessageBox(L"创建成功", L"成功", MB_OK);
OnOK();
return;
}
}
UpdateData(FALSE);
}
回到主文件,我们在导入对应的头文件
#include "CreateFile.h"
然后,我们可以为视图菜单
下的新建文件
添加事件处理程序
// 新建文件
void CResourcesManagementDlg::On32775()
{
UpdateData(TRUE);
// 当前文件路径
g_DirFilePath = m_DriPath;
// 新建文件弹出窗口
CRkCreateFile m_CDlg;
m_CDlg.DoModal();
// 清除并重新填充列表控件
m_FileList.DeleteAllItems();
// 刷新目录
FindDirFile(wcPath);
UpdateData(FALSE);
}
删除文件
同样的,我们可以在菜单视图
下新建删除文件
行,并添加事件处理程序,代码如下:
// 删除文件
void CResourcesManagementDlg::On32773()
{
UpdateData(TRUE);
// 文件类型
CString csDirType = m_FileList.GetItemText(dwIndexFlag, 1);
// 文件路径
CString csFilePath = m_FileList.GetItemText(dwIndexFlag, 2);
if(csDirType == L"文件")
{
// 删除文件
BOOL bRet = DeleteFile(csFilePath);
if (bRet)
{
// 刷新列表
m_FileList.DeleteAllItems();
FindDirFile(wcPath);
}
else
{
MessageBox(L"删除失败", L"提示", MB_OK);
}
return;
}
else
{
MessageBox(L"无法删除目录", L"提示", MB_OK);
}
UpdateData(FALSE);
}
注:此处删除文件
功能做了一些限制,只能删除文件
,而不能删除文件夹
这样,我们就完成简单资源管理器的编写
需要项目源码的可以私信作者~~~