带工具提示、编辑、颜色、列隐藏、排序等功能的 MFC 列表控件。
带工具提示、编辑、颜色、排序、超链接、列隐藏等功能的自绘列表控件。
用于 MFC 应用程序的列表控件
目录
引言
IListEx
是 MFC CMFCListCtrl
类的自绘扩展,具有许多功能
- 可编辑单元格,不仅仅是第一列
- 单元格文本中的超链接
- 单个单元格的工具提示
- 单个单元格的背景和文本颜色
- 使用
LISTEXCOLORSTRUCT
设置列表各个方面的多种单独颜色选项 - 标题高度和字体
- 单个列的标题颜色
- 标题文本和列数据本身的独立对齐
- 标题图标
- 隐藏单个列
- 单个单元格的附加项目数据
- 无需额外努力即可排序列表列的固有能力
- 通过 Ctrl+鼠标滚轮 动态更改列表字体大小
安装
控件的使用很简单
- 将 ListEx.h 和 CListEx 添加到您的项目中
- 声明
IListExPtr
变量:IListExPtr myList { CreateListEx() };
IListExPtr
是指向 IListEx
类的指针,封装在 std::unique_ptr
中。此包装器主要用于方便,因此您不必担心对象的生命周期,它将自动销毁。这就是为什么调用工厂函数 CreateListEx()
来正确初始化指针的原因。
控件使用自己的命名空间 LISTEX
。因此,在声明前是否使用命名空间前缀取决于您
LISTEX::
或在源文件开头定义命名空间
using namespace LISTEX;
Create
手动
Create
是创建列表控件的主要方法。它将 LISTEXCREATE
结构作为参数。
下面是 控件 创建的一个简单示例
IListExPtr myList { CreateListEx() };
.
.
LISTEXCREATE lcs;
lcs.pParent = this;
lcs.uID = ID_MY_LIST;
lcs.rect = CRect(0, 0, 500, 300);
myList->Create(lcs);
在对话框中
要在对话框中创建控件,您可以使用 Create 方法手动完成。
但大多数情况下,您更喜欢通过从 Visual Studio 中的 工具箱 拖放标准 列表控件 到 对话框 模板上。
要使用后一种方法,请遵循以下步骤
- 将工具箱中的标准 列表控件 放置到对话框模板上。为其指定适当的 ID (
IDC_LISTEX
) 并使其达到所需大小。 - 在您的对话框类中声明
IListExPtr
成员变量:IListExPtr m_myList { CreateListEx() };
- 在您的
OnInitDialog
方法中调用m_myList->CreateDialogCtrl(IDC_LISTEX, this);
函数。
工具提示
要为给定单元格设置工具提示,只需编写
myList->SetCellTooltip(0, 1, L"Tooltip text", L"Tooltip caption:");
这将为单元格 (0, 1) 设置工具提示,文本为:Tooltip text,标题为 Tooltip caption。
排序
要启用排序,请将 LISTEXCREATE::fSortable
标志设置为 true。在这种情况下,当您单击标题时,列表将根据单击的列进行排序。默认情况下,IListEx
执行词典排序。
要设置您自己的排序例程,请使用 SetSortable
方法。
编辑单元格
默认情况下,列表控件以只读模式工作。要启用单元格编辑,请调用 SetColumnEditable
方法,并传入您希望其单元格可编辑的列 ID。
数据对齐
经典的 MFC 列表控件只允许同时设置标题和列文本的对齐方式。
ListEx 允许分别为标题和数据设置对齐方式。InsertColumn()
方法中的 iDataAlign
参数正是负责此功能的。
公共方法
IListEx
类还具有一组附加的公共方法,可帮助您在许多不同方面自定义控件。
隐藏列
void HideColumn(int iIndex, bool fHide);
根据 iIndex
隐藏或显示列。
设置单元格颜色
SetCellColor(int iItem, int iSubitem, COLORREF clrBk, COLORREF clrText = -1);
设置给定单元格的背景和文本颜色。
设置单元格数据
void SetCellData(int iItem, int iSubitem, ULONGLONG ullData);
设置与给定单元格关联的任意应用程序定义数据。
设置单元格工具提示
void SetCellTooltip(int iItem, int iSubitem, std::wstring_view wstrTooltip, std::wstring_view wstrCaption = L"");
设置给定单元格的工具提示和标题。
设置列可编辑
void SetColumnEditable(int iColumn, bool fEditable);
启用或禁用给定列的编辑模式。
设置标题列图标
void SetHdrColumnIcon(int iColumn, int iIconIndex, bool fClick = false);
设置给定 iColumn
的标题图像列表中的图标索引。要从列中删除图标,请将 iIconIndex
设置为 -1
。
标志 fClick
表示图标是可点击的。有关更多信息,请参见 LISTEX_MSG_HDRICONCLICK
消息。
设置标题高度
void SetHdrHeight(DWORD dwHeight);
设置可排序
void SetSortable(bool fSortable, PFNLVCOMPARE pfnCompare = nullptr, EListExSortMode enSortMode = EListExSortMode::SORT_LEX)
参数
bool fSortable
启用或禁用排序
PFNLVCOMPARE pfnCompare
回调函数指针,类型为 int (CALLBACK *PFNLVCOMPARE)(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
,用于设置您自己的比较函数。如果为 nullptr
,IListEx
将执行默认排序。
比较函数必须是类的静态成员或非任何类的独立函数。有关更多信息,请参见官方 MSDN 文档。
EListExSortMode enSortMode
列表的默认排序模式。
结构体
LISTEXCREATE
struct LISTEXCREATE {
LISTEXCOLORS stColor { }; //All control's colors.
CRect rect; //Initial rect.
CWnd* pParent { }; //Parent window.
LOGFONTW* pListLogFont { }; //List font.
LOGFONTW* pHdrLogFont { }; //Header font.
UINT uID { }; //List control ID.
DWORD dwStyle { }; //Control's styles. Zero for default.
DWORD dwListGridWidth { 1 }; //Width of the list grid.
DWORD dwHdrHeight { }; //Header height.
bool fDialogCtrl { false }; //If it's a list within dialog.
bool fSortable { false }; //Is list sortable, by clicking on the header column?
bool fLinkUnderline { true }; //Links are displayed underlined or not.
bool fTooltipBaloon { true }; //Baloon type tooltip for cells.
bool fLinkTooltip { true }; //Show links' toolips.
bool fHighLatency { false }; //Do not redraw window until scrolling completes.
};
LISTEXCOLORS
struct LISTEXCOLORS
{
COLORREF clrListText { GetSysColor(COLOR_WINDOWTEXT) }; //List text color.
COLORREF clrListTextLink { RGB(0, 0, 200) }; //List hyperlink text color.
COLORREF clrListTextSel { GetSysColor(COLOR_HIGHLIGHTTEXT) }; //Selected item text color.
COLORREF clrListTextLinkSel { RGB(250, 250, 250) }; //List hyperlink text color in selected cell.
COLORREF clrListTextCellTt { GetSysColor(COLOR_WINDOWTEXT) }; //Text color of a cell that has tooltip.
COLORREF clrListBkRow1 { GetSysColor(COLOR_WINDOW) }; //List Bk color of the odd rows.
COLORREF clrListBkRow2 { GetSysColor(COLOR_WINDOW) }; //List Bk color of the even rows.
COLORREF clrListBkSel { GetSysColor(COLOR_HIGHLIGHT) }; //Selected item bk color.
COLORREF clrListBkCellTt { RGB(170, 170, 230) }; //Bk color of a cell that has tooltip.
COLORREF clrListGrid { RGB(220, 220, 220) }; //List grid color.
COLORREF clrTooltipText { GetSysColor(COLOR_INFOTEXT) }; //Tooltip window text color.
COLORREF clrTooltipBk { GetSysColor(COLOR_INFOBK) }; //Tooltip window bk color.
COLORREF clrHdrText { GetSysColor(COLOR_WINDOWTEXT) }; //List header text color.
COLORREF clrHdrBk { GetSysColor(COLOR_WINDOW) }; //List header bk color.
COLORREF clrHdrHglInact { GetSysColor(COLOR_GRADIENTINACTIVECAPTION) };//Header highlight inactive.
COLORREF clrHdrHglAct { GetSysColor(COLOR_GRADIENTACTIVECAPTION) }; //Header highlight active.
COLORREF clrNWABk { GetSysColor(COLOR_WINDOW) }; //Bk of Non Working Area.
};
此结构也用于 SetColor
方法。
LISTEXCOLOR
struct LISTEXCOLOR
{
COLORREF clrBk { };
COLORREF clrText { };
};
using PLISTEXCOLOR = LISTEXCOLOR*;
LISTEXHDRICON
struct LISTEXHDRICON
{
POINT pt { }; //Point of the top-left corner.
int iIconIndex { }; //Icon index in the header's image list.
bool fClickable { true }; //Is icon sending LISTEX_MSG_HDRICONCLICK message when clicked.
};
EListExSortMode
枚举显示列表列的排序类型。
enum class EListExSortMode : short
{
SORT_LEX, SORT_NUMERIC
};
通知消息
这些消息以 WM_NOTIFY
窗口消息的形式发送到父窗口。lParam
将包含指向 NMHDR
标准 Windows 结构的指针。NMHDR::code
可以是下面描述的 LISTEX_MSG_...
消息之一。
LISTEX_MSG_GETCOLOR
在虚拟模式下,发送到父窗口以检索单元格的颜色。期望响应中包含指向 LISTEXCOLOR
结构的指针,或者不包含任何内容以使用默认值。
void CListDlg::OnListExGetColor(NMHDR* pNMHDR, LRESULT* /*pResult*/)
{
const auto pNMI = reintepret_cast<NMITEMACTIVATE*>(pNMHDR);
//For column number 1 (all rows) set color to RGB(0, 220, 220).
if (pNMI->iSubItem == 1)
{
static LISTEXCOLOR clr { RGB(0, 220, 220), RGB(0, 0, 0) };
pNMI->lParam = reinterpret_cast<LPARAM>(&clr);
}
}
LISTEX_MSG_GETICON
void CListDlg::OnListExGetIcon(NMHDR* pNMHDR, LRESULT* /*pResult*/)
{
//Virtual data icons.
const auto pNMI = reinterpret_cast<NMITEMACTIVATE*>(pNMHDR);
...
pNMI->lParam = SomeIndex; //Icon index in list's image list.
}
此消息在虚拟列表模式下用于获取列表图像列表中的图标索引。
LISTEX_MSG_LINKCLICK
列表嵌入超链接已被点击。WM_NOTIFY
lParam
将指向 NMITEMACTIVATE
结构。
NMITEMACTIVATE::lParam
将包含指向点击超链接的 link
文本的 wchar_t*
指针。iItem
和 iSubItem
成员将包含点击链接的列表项/子项的索引。
超链接语法为:L"带有 嵌入链接 的文本"
如果没有提供可选的 title
标签,则 link
文本本身将用作超链接的工具提示。
链接和标题文本必须用引号 ""
括起来。
LISTEX_MSG_HDRICONCLICK
先前通过 SetHdrColumnIcon
调用设置的标题图标已被点击。
处理此消息的示例代码
BOOL CMyDlg::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult)
{
const auto pNMI = reinterpret_cast<LPNMITEMACTIVATE>(lParam);
if (pNMI->hdr.code == LISTEX_MSG_HDRICONCLICK && pNMI->hdr.idFrom == IDC_MYLIST)
{
const auto pNMI = reinterpret_cast<NMHEADERW*>(lParam);
//pNMI->iItem holds clicked column index.
}
...
LISTEX_MSG_EDITBEGIN
当数据编辑框即将显示时发送。如果您不想让它显示,可以在响应中将 lParam
设置为 0
。
BOOL CMyDlg::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult)
{
const auto pNMI = reinterpret_cast<LPNMITEMACTIVATE>(lParam);
pNMI->lParam = 0; //Edit-box won't show up.
...
LISTEX_MSG_DATACHANGED
在虚拟模式下,当单元格文本发生更改时发送。
BOOL CMyDlg::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult)
{
const auto pNMI = reinterpret_cast<LPNMITEMACTIVATE>(lParam);
const auto iItem = pNMI->iItem;
const auto iSubItem = pNMI->iSubItem;
const pwszNewText = reinterpret_cast<LPCWSTR>(pNMI->lParam);
...
示例
假设您需要一个具有非标准标题高度和黄色背景色的列表控件。没有什么比这更简单的了,请看下面的代码
LISTEXCREATE lcs;
lcs.rect = CRect(0, 0, 500, 300)
lcs.pParent = this;
lcs.dwHdrHeight = 50;
lcs.stColor.clrListBkRow1 = RGB(255, 255, 0);
lcs.stColor.clrListBkRow2 = RGB(255, 255, 0);
myList->Create(lcs);
myList->InsertColumn(...);
myList->InsertItem(...);
在这里,我们将偶数行和奇数行(clrListBkRow1
和 clrListBkRow2
)都设置为相同的黄色。
外观
通过 Ctrl+鼠标滚轮 组合,您可以动态更改列表的字体大小。