让 alpha 混合与 CImageList 一起工作

Getting alpha blending to work with CImageList

我遇到的其他几个问题与此非常相似:

  1. Is it possible to create a CImageList with alpha blending transparency?
  2. Transparent images in ImageLists for ListViews
  3. ImageList Transparency on Listviews?

我使用的是WTL9.0。我有一个框架 window,其子项为 CTreeViewCtrlEx。我正在使用 SHGetFileInfo() 来获取我想在树中使用的图标,但它们显示为黑色背景。这是一个完整的示例。

#define WINVER        0x0601 // Windows 7
#define _WIN32_WINNT  0x0601 // Windows 7

#include <atlbase.h>      
#include <atlapp.h>

CAppModule g_AppModule; // WTL version of CComModule

#include <atlwin.h>
#include <atlframe.h>
#include <atlcrack.h>
#include <atlctrls.h>

class MainWnd : public CFrameWindowImpl<MainWnd>
{
  private:
    typedef MainWnd                    ThisClass;
    typedef CFrameWindowImpl<MainWnd>  BaseClass;

    static const DWORD TREE_STYLE = TVS_HASLINES | TVS_LINESATROOT | 
                                    TVS_HASBUTTONS | WS_CHILD | WS_VISIBLE;

    CTreeViewCtrlEx m_Tree;
    CImageList      m_ImgList;

  public:
    BEGIN_MSG_MAP(ThisClass)
      MSG_WM_CREATE(OnCreate)
      MSG_WM_DESTROY(OnDestroy)
      CHAIN_MSG_MAP(BaseClass)
    END_MSG_MAP()

    LRESULT OnCreate(CREATESTRUCT* pCreateStruct)
    {
      // Create the tree control
      LPCTSTR TREE_CLASS = CTreeViewCtrlEx::GetWndClassName();
      m_Tree.Create(*this, rcDefault, TREE_CLASS, TREE_STYLE);
      m_hWndClient = m_Tree;

      // Create the image list
      m_ImgList.Create(32, 32, ILC_COLOR32, 1, 1);

      SHFILEINFO sFileInfo = { 0 };
      const UINT FLAGS = SHGFI_ICON | SHGFI_USEFILEATTRIBUTES;
      LPCTSTR PATH = _T("C:\Windows");

      // Get the directory icon
      if (0 != ::SHGetFileInfo(PATH, FILE_ATTRIBUTE_DIRECTORY, &sFileInfo,
        sizeof(SHFILEINFO), FLAGS))
      {
        CIcon dirIcon(sFileInfo.hIcon);
        m_ImgList.AddIcon(dirIcon);
      }

      m_Tree.SetImageList(m_ImgList);

      // Insert three items into the tree
      CTreeItem rootItem = 
        m_Tree.InsertItem(_T("Root"), 0, 0, TVI_ROOT, TVI_LAST);
      m_Tree.InsertItem(_T("Sub1"), 0, 0, rootItem, TVI_LAST);
      m_Tree.InsertItem(_T("Sub2"), 0, 0, rootItem, TVI_LAST);
      m_Tree.Expand(rootItem);

      SetMsgHandled(false);
      return 0;
    }

    void OnDestroy()
    {
      if (m_Tree.IsWindow())
        m_Tree.DestroyWindow();

      m_ImgList.Destroy();

      SetMsgHandled(false);
    }
};

int __stdcall WinMain
(
  HINSTANCE hInstance,
  HINSTANCE /*hPrevInstance*/,
  LPTSTR    /*wzCmdLine*/,
  int       nCmdShow
)
{
  g_AppModule.Init(nullptr, hInstance);

  MainWnd mainWindow;
  MSG msg = { 0 };

  if (nullptr == mainWindow.CreateEx())
    return 1;

  mainWindow.ShowWindow(nCmdShow);
  mainWindow.UpdateWindow();

  while (0 < ::GetMessage(&msg, nullptr, 0, 0))
  {
    ::TranslateMessage(&msg);
    ::DispatchMessage(&msg);
  }

  g_AppModule.Term();

  return 0;
}

上面的第三个link似乎暗示我需要从图标中获取位图,复制它然后将其添加到图像列表中。

然而,查看 this project 的代码意味着您应该能够简单地使用图标本身。如果您深入研究提供的 class,它只是使用图标句柄将其添加到列表中。这种比较的问题在于它是在 C# 中,情况可能有所不同。

This MSDN article 表示支持 32 位 alpha 混合图标,但我还没有让它们工作。

我已经获得了在提供的代码中加载的图标的位图并查看像素数据,图像确实 包含 alpha 通道并被列为 32 位。

如果有人知道如何让这个工作,你能告诉我吗?

编辑: 这是我通过发布的代码得到的图像。

代码没问题,但是 Windows 没有被告知正在使用的通用控件的版本。

您必须启用 Visual Style。您可以在项目清单中执行此操作,或者至少在您的 *.cpp 文件之一中包含以下行:

#pragma comment(linker,"/manifestdependency:\"type='win32' \
name='Microsoft.Windows.Common-Controls' version='6.0.0.0' \
processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")

请注意此 #pragma 指令是 Visual Studio 特定的,请将清单与其他编译器一起使用。

此外,您可以添加对 windows 主题的支持:

#include <UxTheme.h>
#pragma comment( lib, "UxTheme.lib" )
...    
SetWindowTheme(tree.m_hWnd, L"Explorer", NULL);

结果: