CFileDropListCtrl 类的实现与使用

在Windows应用程序开发中,经常需要实现文件选择功能。传统的方法是通过对话框让用户选择文件,但这种方式对于选择多个文件来说并不方便。为了提高用户体验,可以使用拖放的方式来选择文件。本文将介绍一个基于MFC的CListCtrl类——CFileDropListCtrl,它允许用户从资源管理器中拖放文件或文件夹到列表控件中。

概述

CFileDropListCtrl 是一个从 CListCtrl 派生的类,它接受从资源管理器拖放的文件和/或文件夹。它可以根据文件扩展名过滤文件类型,解析快捷方式,检查重复项,并且允许通过可选的用户回调函数自定义处理拖放的项。这个类是为了解决 CFileDialog 在多文件选择方面的可用性问题而开发的,并且更适合有经验的用户。

CFileDialog 用于选择文件添加到列表控件中,这在某些情况下是可行的,但是从不同的文件夹中选择多个文件通常很繁琐,尤其是在 NT 和 95 上 CFileDialog 的小尺寸(在 98 和 2000 上可以调整大小)。使用 Windows 资源管理器定位文件并将它们拖放到列表控件上要简单得多,对于有经验的用户来说也更直观。

如何在项目中使用

可以通过替换原始的 CListCtrl 并指定想要接受的拖放项类型,快速地将此功能添加到新项目或现有项目中。默认情况下,列表会自己插入项——对于每一个项调用 CListCtrl::InsertItem(0, csFilename)。这将适用于拥有的任何风格的列表(小图标、大图标、列表、报告)。

请注意,如果关联了一个图像列表,将使用默认图像(索引 0),在报告视图中,文件名将被插入到第一列。如果想要更高级的功能,比如在报告视图中有几列并显示每个文件的大小和属性,可以!给控件一个回调函数,它将在每次合适的文件被拖放时通知——然后由来插入它,详见下文。

CFileDropListCtrl 有两个公共成员用于更新和检索设置:

BOOL SetDropMode(const CFileDropListCtrl::DROPLISTMODE& dropMode); DROPLISTMODE GetDropMode() const;

结构 DROPLISTMODE:

struct DROPLISTMODE { UINT iMask; CString csFileExt; LPFN_DROP_FILES_CALLBACK pfnCallback; };

iMask:指定接受哪种类型的项——这些标志的组合:

FileDropListCtrl::DL_ACCEPT_FILES 允许拖放文件 CFileDropListCtrl::DL_ACCEPT_FOLDERS 允许拖放文件夹 CFileDropListCtrl::DL_FILTER_EXTENSION 只接受指定扩展名的文件。在 csFileExt 中指定 CFileDropListCtrl::DL_USE_CALLBACK 为每个拖放的项接收回调,指定在 pfnCallback 中 CFileDropListCtrl::DL_ALLOW_DUPLICATES 即使路径名已经在列表中,也接受路径名(如果通过回调函数处理插入,则忽略)

csFileExt:要过滤的文件扩展名。使用格式 ".extension"。除非指定了 DL_FILTER_EXTENSION,否则忽略。

pfnCallback:回调函数的地址。除非指定了 DL_USE_CALLBACK,否则忽略。

SetDropMode() 返回值:

- TRUE 如果模式成功更改 - FALSE 如果模式无效(指定了 DL_USE_CALLBACK,但没有填充 pfnCallback)。将使用默认设置(接受文件和文件夹,不允许重复项)

如何添加和使用

在资源编辑器中,向对话框添加一个列表控件,并在“扩展样式”页面上检查“接受文件”属性。

将列表样式设置为“列表”,除非使用回调函数自己插入项。请记住,如果选择“报告”样式,必须在插入任何项之前插入一列。

使用类向导为列表分配一个 CListCtrl 成员变量,例如 m_List。

现在在对话框类的头文件中:

#include "FileDropListCtrl.h"

并将列表成员变量类型从 CListCtrl 更改为 CFileDropListCtrl:

CFileDropListCtrl m_List;

现在可以指定列表控件要接受哪种类型的项。在这种情况下,最好将其放在对话框类的 OnInitDialog() 中:

CFileDropListCtrl::DROPLISTMODE dropMode; dropMode.iMask = CFileDropListCtrl::DL_ACCEPT_FILES | CFileDropListCtrl::DL_FILTER_EXTENSION; dropMode.csFileExt = _T(".txt"); m_List.SetDropMode(dropMode);

这将设置列表只接受扩展名为 ".txt" 的文件。

注意:默认模式是接受所有类型的文件和文件夹,但不允许重复条目。

可选地指定一个回调函数。如果没有这个,控件将负责将项插入到列表中,尽管很简单。如果想要更高级的功能,应该安装一个回调——控件将使用这个在每次合适的文件被拖放时通知——然后由来插入它。

在对话框类中声明回调作为静态成员函数,或者作为全局函数:

static HRESULT CALLBACK OnListFileDropped(CListCtrl* pList, const CString& csPathname, const UINT& iPathType );

在 OnInitDialog() 中注册回调以及其他信息——类似于步骤 4:

dropMode.iMask |= CFileDropListCtrl::DL_USE_CALLBACK; dropMode.pfnCallback = CMyDialog::OnListFileDropped;

以下是一个自定义插入的示例,通过显示拖放文件的大小:

HRESULT CMyDialog::OnListFileDropped(CListCtrl* pList, const CString& csPathname, const UINT& iPathType ); { // 仅对文件执行此操作。 if (CFileDropListCtrl::DL_FILE_TYPE == iPathType) { // 获取其大小 CString csFileSize = GetFileSize(csPathname); // 在第一列插入文件名 int nItem = pList->InsertItem(0, csPathname, IMAGE_INDEX); // 在第二列插入大小 pList->SetItemText(nitem, 1, csFileSize); } return S_OK; }

所有代码都完成了。现在将输入库 "shlwapi.lib" 添加到项目的链接设置中。这是为了 PathFindExtension(),这是许多有用的 Shell 实用程序函数之一。

工作原理

处理拖放文件的方法是通用的,可以应用于任何从 CWnd 派生的控件(例如 CEdit)。只需要处理和覆盖 2 条消息——WM_CREATE 和 WM_DROPFILES:

CWnd::OnCreate()——调用 DragAcceptFiles(TRUE) 以注册动态创建的窗口作为拖放目标。

CWnd::OnDropFiles()——处理文件:

以下是一个在子类化的 CEdit 控件中处理 WM_DROPFILES 的示例:

void CMyEdit::OnDropFiles(HDROP dropInfo) { // 获取拖放的路径名(文件或文件夹)数量 UINT nNumFilesDropped = DragQueryFile(dropInfo, 0xFFFFFFFF, NULL, 0); // 迭代它们并做一些有趣的事情 TCHAR szFilename[MAX_PATH + 1]; for (UINT nFile = 0; nFile < nNumFilesDropped; nFile++) { // 获取路径名 DragQueryFile(dropInfo, nFile, szFilename, MAX_PATH + 1); // 用它做一些事情...这只是一个示例 CString csText; GetWindowText(csText); SetWindowText(csText + _T("; ") + szFilename); } // Windows 分配了文件信息的内存,所以必须清理它 DragFinish(dropInfo); }

此外,可能希望在处理文件名之前展开任何拖放的快捷方式,所以请查看 CFileDropListCtrl::ExpandShortcut()。它使用 COM 接口 IShellLink 来解析它们。

沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485