无法获取Windows覆盖图标在TListView中工作 [英] Can't get Windows Overlay icons to work in TListView
问题描述
使用Borland C ++ Builder 2009我可以在 TListView
对象中显示重叠图标,使用我自己的 TImageList
/ p>
但是,我也需要这个来使用Windows图标。显示这些图标不是问题,但我无法使覆盖图标工作。
这里是我做的(不完成,代码从更大的项目,但它应该正确地说明问题):
在Init期间:
SHFILEINFO info;
SmallSystemIconsList-> Handle = SHGetFileInfo(L,
0,
& info,
sizeof(info),
SHGFI_ICON |
SHGFI_SMALLICON |
SHGFI_SYSICONINDEX |
SHGFI_OVERLAYINDEX
);
DestroyIcon(info.hIcon);`
每次我想知道图标:
SHFILEINFO信息;
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;
我注意到在测试期间传递了正确的值。例如,当文件名为某事。 lnk 时, ListItem-> OverlayIndex
b $ b
但重叠图标未显示。我相信我错过了一些东西。要获得覆盖图标使用我自己的 TImageList
对象,我不得不调用 ImageList-> Overlay()
。我不知道我是否需要在Windows列表中执行相同的操作,但是我不确定要使用什么值。
SHGetFileInfo()
返回的覆盖索引是从1开始的,但是 TListItem :: OverlayIndex
属性期望一个0基于索引,然后在使用Win32 API更新列表项时,它将转换为基于1的索引。因此您需要在分配 OverlayIndex
时减去1:
> OverlayIndex =(info.iIcon>> 24)-1;
您不需要调用 TImageList :: Overlay
CN_NOTIFY / code>消息而不是 WM_NOTIFY
。 将WM_NOTIFY
传送到ListView的父窗口 ,并反映到 CN_NOTIFY
VCL。此外,您需要在声明您的本地 LVITEM
变量时使用引用,否则您正在修改消息数据中的原始 LVITEM
。此外,当分配 item.state
和 item.stateMask
时,需要使用 |
添加默认处理程序分配的现有值。 $ b =
$ b void __fastcall TForm1 :: LVNewWindowProc(Messages :: TMessage& Msg)
{
if(LVOldWindowProc)LVOldWindowProc ;
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;
}
}
Using Borland C++ Builder 2009 I can display overlay icons in a TListView
object, using my own TImageList
.
However I also need this to work with the Windows icons. Showing those icons is not a problem, but I can't get Overlay icons to work (yet).
Here's what I do (not complete and code lifted out of a bigger project, but it should illustrate the question properly) :
During Init:
SHFILEINFO info ;
SmallSystemIconsList->Handle = SHGetFileInfo( L"",
0,
&info,
sizeof(info),
SHGFI_ICON |
SHGFI_SMALLICON |
SHGFI_SYSICONINDEX |
SHGFI_OVERLAYINDEX
) ;
DestroyIcon(info.hIcon) ;`
Everytime I want to know the index of an icon:
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;
I notice that the proper values are being passed during testing. For instance ListItem->OverlayIndex
is assigned value 2 when the Filename is 'something.lnk'.
But the overlay icon is not showing. I'm sure I'm missing something. To get overlay icons to work with my own TImageList
objects I had to call ImageList->Overlay()
. I wonder if I need to do the same with the Windows list, but I'm not sure what values to use then.
解决方案 The overlay index returned by SHGetFileInfo()
is 1-based, but the TListItem::OverlayIndex
property expects a 0-based index, which it then converts to 1-based when updating the list item using the Win32 API. So you need to subtract 1 when assigning the OverlayIndex
:
ListItem->OverlayIndex = (info.iIcon >> 24) - 1;
You DO NOT need to call TImageList::Overlay()
when using a system image list.
Update: your subclass needs to look for the CN_NOTIFY
message instead of WM_NOTIFY
. WM_NOTIFY
is delivered to the ListView's parent window and reflected back to the ListView as CN_NOTIFY
by the VCL. Also, you need to use a reference when declaring your local LVITEM
variable, otherwise you are modifying a copy instead of the original LVITEM
that is in the message data. Also, when assigning item.state
and item.stateMask
, you need to use the |=
operator to append your overlay values to them instead of replacing the existing values that were assigned by the default handler.
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;
}
}
这篇关于无法获取Windows覆盖图标在TListView中工作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!