无法使 Windows 覆盖图标在 TListView 中工作
Can't get Windows Overlay icons to work in TListView
使用 Borland C++ Builder 2009,我可以使用我自己的 TImageList
.
在 TListView
对象中显示覆盖图标
但是我还需要它来处理 Windows 图标。显示这些图标不是问题,但我无法让叠加图标工作(目前)。
这是我所做的(不完整,代码是从一个更大的项目中提取出来的,但它应该能正确地说明问题):
初始化期间:
SHFILEINFO info ;
SmallSystemIconsList->Handle = SHGetFileInfo( L"",
0,
&info,
sizeof(info),
SHGFI_ICON |
SHGFI_SMALLICON |
SHGFI_SYSICONINDEX |
SHGFI_OVERLAYINDEX
) ;
DestroyIcon(info.hIcon) ;`
每次想知道图标的索引:
SHFILEINFO info ;
SHGetFileInfo( MyFileName.c_str(),
FILE_ATTRIBUTE_NORMAL,
&info,
sizeof(SHFILEINFO) ,
SHGFI_ICON |
SHGFI_USEFILEATTRIBUTES |
SHGFI_OVERLAYINDEX
) ;
DestroyIcon(info.hIcon) ;
// TListItem *ListItem
ListItem->ImageIndex = (info.iIcon & 0x00FFFFFF) ;
ListItem->OverlayIndex = (info.iIcon >> 24) - 1;
我注意到在测试期间传递了正确的值。例如,当文件名是 'something.lnk'.
时,ListItem->OverlayIndex
被赋值为 2
但是叠加图标没有显示。我确定我错过了什么。为了让覆盖图标与我自己的 TImageList
对象一起工作,我必须调用 ImageList->Overlay()
。我想知道我是否需要对 Windows 列表做同样的事情,但我不确定那时要使用什么值。
SHGetFileInfo()
返回的覆盖索引是基于 1 的,但是 TListItem::OverlayIndex
属性 需要一个基于 0 的索引,然后在更新时将其转换为基于 1使用 Win32 API 的列表项。所以你需要在分配 OverlayIndex
:
时减去 1
ListItem->OverlayIndex = (info.iIcon >> 24) - 1;
使用系统图像列表时,您不需要调用 TImageList::Overlay()
。
更新:您的子类需要查找 CN_NOTIFY
消息而不是 WM_NOTIFY
。 WM_NOTIFY
传递给 ListView 的 父级 window 并由 VCL 作为 CN_NOTIFY
反射回 ListView。此外,您需要在声明本地 LVITEM
变量时使用 reference,否则您修改的是 copy 而不是 [=消息数据中的 31=]original LVITEM
。此外,在分配 item.state
和 item.stateMask
时,您需要使用 |=
运算符 向它们附加 您的叠加值,而不是 替换默认处理程序分配的现有值。
void __fastcall TForm1::LVNewWindowProc(Messages::TMessage &Msg)
{
if (LVOldWindowProc) LVOldWindowProc(Msg);
if ((Msg.Msg == CN_NOTIFY) &&
(reinterpret_cast<LPNMHDR>(Msg.LParam)->code == LVN_GETDISPINFOW))
{
LV_ITEM &item = reinterpret_cast<LV_DISPINFO*>(Msg.LParam)->item;
TListItem *ListItem = ListView1->Items->Items[item.iItem];
item.mask |= LVIF_STATE;
item.state |= INDEXTOOVERLAYMASK(ListItem->OverlayIndex + 1);
item.stateMask |= LVIS_OVERLAYMASK;
}
}
使用 Borland C++ Builder 2009,我可以使用我自己的 TImageList
.
TListView
对象中显示覆盖图标
但是我还需要它来处理 Windows 图标。显示这些图标不是问题,但我无法让叠加图标工作(目前)。
这是我所做的(不完整,代码是从一个更大的项目中提取出来的,但它应该能正确地说明问题):
初始化期间:
SHFILEINFO info ;
SmallSystemIconsList->Handle = SHGetFileInfo( L"",
0,
&info,
sizeof(info),
SHGFI_ICON |
SHGFI_SMALLICON |
SHGFI_SYSICONINDEX |
SHGFI_OVERLAYINDEX
) ;
DestroyIcon(info.hIcon) ;`
每次想知道图标的索引:
SHFILEINFO info ;
SHGetFileInfo( MyFileName.c_str(),
FILE_ATTRIBUTE_NORMAL,
&info,
sizeof(SHFILEINFO) ,
SHGFI_ICON |
SHGFI_USEFILEATTRIBUTES |
SHGFI_OVERLAYINDEX
) ;
DestroyIcon(info.hIcon) ;
// TListItem *ListItem
ListItem->ImageIndex = (info.iIcon & 0x00FFFFFF) ;
ListItem->OverlayIndex = (info.iIcon >> 24) - 1;
我注意到在测试期间传递了正确的值。例如,当文件名是 'something.lnk'.
时,ListItem->OverlayIndex
被赋值为 2
但是叠加图标没有显示。我确定我错过了什么。为了让覆盖图标与我自己的 TImageList
对象一起工作,我必须调用 ImageList->Overlay()
。我想知道我是否需要对 Windows 列表做同样的事情,但我不确定那时要使用什么值。
SHGetFileInfo()
返回的覆盖索引是基于 1 的,但是 TListItem::OverlayIndex
属性 需要一个基于 0 的索引,然后在更新时将其转换为基于 1使用 Win32 API 的列表项。所以你需要在分配 OverlayIndex
:
ListItem->OverlayIndex = (info.iIcon >> 24) - 1;
使用系统图像列表时,您不需要调用 TImageList::Overlay()
。
更新:您的子类需要查找 CN_NOTIFY
消息而不是 WM_NOTIFY
。 WM_NOTIFY
传递给 ListView 的 父级 window 并由 VCL 作为 CN_NOTIFY
反射回 ListView。此外,您需要在声明本地 LVITEM
变量时使用 reference,否则您修改的是 copy 而不是 [=消息数据中的 31=]original LVITEM
。此外,在分配 item.state
和 item.stateMask
时,您需要使用 |=
运算符 向它们附加 您的叠加值,而不是 替换默认处理程序分配的现有值。
void __fastcall TForm1::LVNewWindowProc(Messages::TMessage &Msg)
{
if (LVOldWindowProc) LVOldWindowProc(Msg);
if ((Msg.Msg == CN_NOTIFY) &&
(reinterpret_cast<LPNMHDR>(Msg.LParam)->code == LVN_GETDISPINFOW))
{
LV_ITEM &item = reinterpret_cast<LV_DISPINFO*>(Msg.LParam)->item;
TListItem *ListItem = ListView1->Items->Items[item.iItem];
item.mask |= LVIF_STATE;
item.state |= INDEXTOOVERLAYMASK(ListItem->OverlayIndex + 1);
item.stateMask |= LVIS_OVERLAYMASK;
}
}