【问题标题】:Can't get Windows Overlay icons to work in TListView无法让 Windows 覆盖图标在 TListView 中工作
【发布时间】:2015-07-18 13:42:03
【问题描述】:

使用 Borland C++ Builder 2009 我可以在 TListView 对象中显示覆盖图标,使用我自己的 TImageList

不过,我还需要它来处理 Windows 图标。显示这些图标不是问题,但我无法让 Overlay 图标正常工作。

这就是我所做的(不完整并且代码从一个更大的项目中提取出来,但它应该正确地说明问题):

在初始化期间:

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 列表执行相同的操作,但我不确定要使用哪些值。

【问题讨论】:

    标签: c++ winapi c++builder


    【解决方案1】:

    SHGetFileInfo() 返回的覆盖索引是从 1 开始的,但 TListItem::OverlayIndex 属性需要一个从 0 开始的索引,然后在使用 Win32 API 更新列表项时将其转换为从 1 开始。所以分配OverlayIndex时需要减1:

    ListItem->OverlayIndex  = (info.iIcon >> 24) - 1;
    

    使用系统映像列表时,您无需调用TImageList::Overlay()

    更新:您的子类需要查找CN_NOTIFY 消息而不是WM_NOTIFYWM_NOTIFY 被传递到 ListView 的 父窗口 并由 VCL 作为 CN_NOTIFY 反射回 ListView。此外,您需要在声明本地 LVITEM 变量时使用 reference,否则您正在修改 copy 而不是 original @987654332 @ 即在消息数据中。此外,在分配item.stateitem.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;
        }
    }
    

    【讨论】:

    • 谢谢雷米,不幸的是,这也不起作用?我看不到任何覆盖图标,而不仅仅是错误的图标。感谢您的修复,但我可能需要做些什么才能真正看到覆盖图标?
    • 我向你保证,它确实有效,因为我在发布之前对其进行了测试,并且确实看到了正确的覆盖图标。
    • 对,这是在一个新的测试项目(又名默认设置)中带有一个“新”TListView 对象吗?我也会试试的。我在旧的现有代码中这样做,我想知道我的 ListView 对象中的设置是否搞砸了?
    • 是的,我已经用一个新项目对其进行了测试。
    • 这是 TListView 的一个已知且长期存在的问题,并且在 QC 中仍然存在:#55905 TListview overlay images not drawn with OwnerData
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-25
    • 2014-11-21
    • 2019-06-30
    • 1970-01-01
    • 2011-12-11
    • 2010-12-05
    相关资源
    最近更新 更多