65.9K
CodeProject 正在变化。 阅读更多。
Home

透明控件的通用解决方案

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.80/5 (20投票s)

2008年10月14日

CPOL

2分钟阅读

viewsIcon

81339

downloadIcon

8226

一种非常简单、集成的方法,使诸如按钮、滑块控件和进度控件等控件在对话框中具有透明效果。

引言

在UI开发中,我们通常需要实现一些漂亮的特效,而使某些控件具有透明效果是我们经常遇到的问题。 在本文中,我介绍了一种实现控件透明度的方法。 源代码包含基于 Win32 API 的类 CTransparentHelper,它可以在 MFC、ATL、WTL、Win32 应用程序中使用,也可能在其他框架中使用。 我开发了一个新版本,因为我在工作中使用了它,所以如果您有任何建议、错误报告或问题,请发送给我。 此外,您还可以访问 我的技术博客 以获取更多信息。

背景

我编写此代码是因为我需要一些透明控件,例如按钮、滑块控件和进度控件。 我发现当父窗口移动或控件移动时,在线上的一些方法无效;当我们希望在可调整大小的对话框中使用透明控件时,这是一个问题。 因此,我编写了 CTransparentHelper; 当调用 MoveWindow 时,您可以获得平滑的透明效果,并且该类适用于所有控件。

特点

  • 没有框架依赖。
  • 可用于不同类型的控件。
  • 可用于多层透明。
  • 在现有代码中使用简单。

使用代码

在介绍如何使用源代码之前,我建议使用内存 DC 来存储父对话框的背景 DC。 这对于子控件的透明度很方便,并且还提高了绘图效率。 有关详细信息,请参阅源代码。

包含 “TransparentHelper.h”

在需要透明的控件的文件中包含 “TransparentHelper.h”。 并添加一个类型为 CTransparentHelper 的对象。

#pragma once
 
#include "TransparentHelper.h"
// CSliderCtrlEx
 
class CSliderCtrlEx : public CSliderCtrl
{
    ………
    CTransparentHelper m_objTrans;
}

初始化 CTransparentHelper 对象

void CSliderCtrlEx::PreSubclassWindow()
{

    // TODO: Add your specialized code here and/or call the base class
    …….

    CSliderCtrl::PreSubclassWindow();
    m_objTrans.Install( GetSafeHwnd());
    ……
}

在您需要时调用 CTransparentHelper 的 TransparentBk 函数

BOOL CSliderCtrlEx::OnSliderDrawChannel( CDC* pDC, CRect& rect, UINT nState)
{
    ……
    if ( m_objTrans.IsValid() )
    {
        m_objTrans.TransparentBk( pDC->GetSafeHdc(), GetSafeHwnd());
    }
    ………
    return TRUE;
}

将代码添加到控件的父窗口

有时,父窗口是一个对话框。 我需要处理消息 WM_TRANSPARENT_BK,该消息从透明控件发送,以便获取 DC。

LRESULT CTransparentControlDlg::OnTransaprentBk( WPARAM wParam, LPARAM lParam)
{
    HDC hdc = ( HDC)wParam;
    HWND hwnd = ( HWND)lParam;

    CTransparentHelper::OnTranparentControl( m_pMemDC->GetSafeHdc(), 
                                           (WPARAM)hdc, (LPARAM)hwnd);
    return TRUE;
}

备注:m_pMemDC 是对话框的内存 DC,当对话框的大小改变时,它将会改变。

当背景改变时通知子控件

当对话框的内存 DC 改变时,它必须通知带有透明标签的子控件。

void CTransparentControlDlg::BuildBkDC()
{
    //rebuild the background dc
    ........
    //when the parent dialog's background is rebuild, 
    //notify the child which has an transparent tag.
    CTransparentHelper::NotifyTransparentChild( GetSafeHwnd());
}

消息 WM_NOTIFY_TRANSPARENT

当背景改变时,透明控件需要处理由父控件发送的消息 WM_NOTIFY_TRANSPARENT

LRESULT CSliderCtrlEx::OnNotifyTransparent( WPARAM wParam, LPARAM lParam) 
{
    if ( ::IsWindowEnabled( GetSafeHwnd()))
    {
        ::EnableWindow( GetSafeHwnd(),FALSE); 
        ::EnableWindow( GetSafeHwnd(),TRUE);
    }
    else
    {
        ::EnableWindow( GetSafeHwnd(),TRUE); 
        ::EnableWindow( GetSafeHwnd(),FALSE);
    }
    //This operation is for the repaint of slider control, 
    //because Invalidate cann't bring the NM_CUSTOMDRAW message.
    //M..., this may not the best method to solve the problem. 
    //If you have other method, please tell me.

    return TRUE;
}

备注:对于某些绘图方法下的某些控件(例如,NM_CUSTOMDRAW),Invalidate 不会引起真正的重绘。 因此,我添加了 WM_NOTIFY_TRANSAPRENT 消息以使其兼容。 如果透明控件在调用 Invalidate 后会自行重绘,则它不需要处理该消息。

© . All rights reserved.