无法获取Windows覆盖图标在TListView中工作 [英] Can't get Windows Overlay icons to work in TListView

查看:314
本文介绍了无法获取Windows覆盖图标在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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆