一、先说使用方法:
1,如下,先建按常规方式一对话框,生成对话框类,
2,将继承类直接改为CLS_DlgBaseLayered如:
class CLS_DLGTool : public CLS_DlgBaseLayered
3,修改构造及消息宏的继承类,如:
IMPLEMENT_DYNAMIC(CLS_DLGTool, CLS_DlgBaseLayered)
CLS_DLGTool::CLS_DLGTool(CWnd* pParent /*=NULL*/)
: CLS_DlgBaseLayered(CLS_DLGTool::IDD, pParent)
BEGIN_MESSAGE_MAP(CLS_DLGTool, CLS_DlgBaseLayered)
4,OnInitDialog中添加继承:
BOOL CLS_DLGTool::OnInitDialog()
{
CLS_DlgBaseLayered::OnInitDialog();
-----
5,调用方法:
m_dlgTool.SetFlagName("d:\\pic\\transparent22.jpg");
m_dlgTool.Create(IDD_DIALOG_SYSTEM_TOOL, this);
CRect rcTool;
m_dlgTool.GetClientRect(&rcTool);
int iToolW = rcTool.Width();
int iToolH = rcTool.Height();
rcTool.left = rc.right - rcTool.Width();
rcTool.right = rc.right;
rcTool.top = rc.top + (rc.Height() - rcTool.Height())/2;
rcTool.bottom = rcTool.top + iToolH;
ScreenToClient(&rcTool);
m_dlgTool.MoveWindow(&rcTool);
m_dlgTool.ShowWindow(SW_SHOW);
二,类定义如下:
对话框模板类:CLS_DlgBaseLayered.h头文件
#pragma once
/*
层对话框基类,可带关键色,有透明度,可依指定透明色的图形生成异形层。
注意此对话框如为子对话框则失去透明度功能。分层不支持子控件,可为弹出或非模态。
Create创建前调用:SetTransparentParam 否则使用默认
如需要异形窗口或图形窗口也须创建前调用:SetFlagName加载图形
*/
// CLS_DlgBaseLayered dialog
const COLORREF CONST_crDefault = RGB(1,0,0);
const int CONST_iTransparentLevelDefault = 150;//0--255
const int CONST_iTransparentMaskDefault = LWA_COLORKEY|LWA_ALPHA;
class CLS_DlgBaseLayered : public CDialog
{
DECLARE_DYNAMIC(CLS_DlgBaseLayered)
public:
CLS_DlgBaseLayered(UINT nIDTemplate,CWnd* pParent = NULL); // standard constructor
virtual ~CLS_DlgBaseLayered();
// Dialog Data
//enum { IDD = IDD_LS_DLGBASELAYERED };
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
DECLARE_MESSAGE_MAP()
//SetLayeredWindowAttributes(m_hWnd,RGB(1,0,0),150,LWA_COLORKEY|LWA_ALPHA);
//后三个参数对应以下三个变量。
COLORREF m_crMark;//关键色 也即透明色
int m_iTransparentLevel;//透明度
int m_iLayerMask;//层透明模式 关键色还是透明度或二者都有。
CString m_cstrFlagFile;//图片文件,主要是决定窗口形状。
CImage *m_pImage;//图片对象指针。
void RefreshFlag(CDC* pDC);
void RefreshFlag();
void CreateRgnFromPicEx( CString _cstrPic );//此接口只取非透明区域
void CreateRgnFromPic( CString _cstrPic );//此接口只取透明区域 暂未使用
HCURSOR m_hCursor;//移动时的鼠标形状。
bool m_blCanMove; //是否可移动
public:
void SetMovable(bool _blCanMove = true);
//可以使用异型窗口,取自图形。
void SetFlagName(CString _cstrFlagName);
virtual BOOL OnInitDialog();
void SetTransparentParam(COLORREF _crMark,int _iTransparentLevel,int _iLayerMask);
afx_msg BOOL OnEraseBkgnd(CDC* pDC);
afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
afx_msg BOOL OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message);
//以下按钮响应纯是为了防止回车,ESC等造成窗口退出,继承对话框可自行实现其它。
afx_msg void OnBnClickedOk();
afx_msg void OnBnClickedCancel();
};
实现文件:CLS_DlgBaseLayered.cpp
// CLS_DlgBaseLayered.cpp : implementation file
//
#include "stdafx.h"
#include "CLS_DlgBaseLayered.h"
// CLS_DlgBaseLayered dialog
IMPLEMENT_DYNAMIC(CLS_DlgBaseLayered, CDialog)
CLS_DlgBaseLayered::CLS_DlgBaseLayered(UINT nIDTemplate,CWnd* pParent /*=NULL*/)
: CDialog(nIDTemplate, pParent)
{
m_crMark = CONST_crDefault;
m_iTransparentLevel = CONST_iTransparentLevelDefault;
m_iLayerMask = CONST_iTransparentMaskDefault;
m_cstrFlagFile = "";
m_pImage = NULL;
m_blCanMove = false;
m_hCursor = LoadCursor(NULL,IDC_SIZEALL);
}
CLS_DlgBaseLayered::~CLS_DlgBaseLayered()
{
if (m_pImage)
{
m_pImage->Destroy();
delete m_pImage;
m_pImage = NULL;
}
DeleteObject(m_hCursor);
m_hCursor = NULL;
}
void CLS_DlgBaseLayered::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
}
BEGIN_MESSAGE_MAP(CLS_DlgBaseLayered, CDialog)
ON_WM_ERASEBKGND()
ON_WM_LBUTTONDOWN()
ON_WM_SETCURSOR()
ON_BN_CLICKED(IDOK, &CLS_DlgBaseLayered::OnBnClickedOk)
ON_BN_CLICKED(IDCANCEL, &CLS_DlgBaseLayered::OnBnClickedCancel)
END_MESSAGE_MAP()
// CLS_DlgBaseLayered message handlers
BOOL CLS_DlgBaseLayered::OnInitDialog()
{
CDialog::OnInitDialog();
SetWindowLong(m_hWnd,GWL_EXSTYLE,
GetWindowLong(m_hWnd,GWL_EXSTYLE)^WS_EX_LAYERED);
::SetLayeredWindowAttributes(m_hWnd,m_crMark,m_iTransparentLevel,m_iLayerMask);
if(m_cstrFlagFile.GetLength() > 0)
{
CreateRgnFromPicEx(m_cstrFlagFile);
//RefreshFlag();
}
return TRUE;
}
void CLS_DlgBaseLayered::SetTransparentParam( COLORREF _crMark,int _iTransparentLevel,int _iLayerMask )
{
m_crMark = _crMark;
m_iTransparentLevel = _iLayerMask;
m_iLayerMask = _iLayerMask;
}
BOOL CLS_DlgBaseLayered::OnEraseBkgnd(CDC* pDC)
{
RefreshFlag(pDC);
return TRUE;
}
void CLS_DlgBaseLayered::RefreshFlag(CDC* pDC)
{
CRect rc;
GetClientRect(&rc);
if (m_pImage)
{
CDC memDc;
memDc.CreateCompatibleDC(pDC);
HBITMAP hOldBmp = (HBITMAP)memDc.SelectObject(m_pImage->operator HBITMAP());
pDC->StretchBlt(0,0, rc.Width(),rc.Height(), &memDc, 0,0, m_pImage->GetWidth(),m_pImage->GetHeight(), SRCCOPY);
memDc.SelectObject(hOldBmp);
memDc.DeleteDC();
}
else
{
pDC->FillSolidRect(&rc,m_crMark);
}
}
void CLS_DlgBaseLayered::RefreshFlag()
{
CDC* pDC = CDC::FromHandle(::GetDC(GetSafeHwnd()));
RefreshFlag(pDC);
::ReleaseDC(GetSafeHwnd(), pDC->GetSafeHdc());
}
void CLS_DlgBaseLayered::SetFlagName( CString _cstrFlagName )
{
m_cstrFlagFile = _cstrFlagName;
}
void CLS_DlgBaseLayered::CreateRgnFromPicEx( CString _cstrPic )
{
if (!m_pImage)
{
m_pImage = new CImage;
}
else
{
m_pImage->Destroy();
}
m_pImage->Load(_cstrPic);
if (m_pImage->IsNull())
{
AfxMessageBox("请正确选择图象文件");
return ;
}
CBitmap cBitmap;
cBitmap.Attach(m_pImage->operator HBITMAP());//加载描述窗口形状的BMP图片
CRect rc;
GetWindowRect(&rc);//获得窗体区域
rc.right = rc.left+m_pImage->GetWidth();
rc.bottom = rc.top +m_pImage->GetHeight();
//MoveWindow(&rc,TRUE);//窗口大小等同图片大小。
int x, y;
CRgn mainRgn, currentRgn;
CDC* pDC = GetDC();//获得设备上下文
CDC memDC;
CBitmap bitmap;//声明位图对象
CBitmap* pOldMemBmp = NULL;
COLORREF currentColor;//当前像素颜色
memDC.CreateCompatibleDC(pDC);//创建与内存兼容的设备上下文
pOldMemBmp = memDC.SelectObject(&cBitmap);
mainRgn.CreateRectRgn(0, 0, rc.Width(), rc.Height());//初始化区域
COLORREF TransColor=memDC.GetPixel(0,0);//透明色取第一象素色。
int minX=0,MaxX=rc.Width(),minY=0,MaxY=rc.Height();
for (x = 0; x <= rc.Width(); x++)
{
for (y = 0; y <= rc.Height(); y++)
{
//将透明部分去掉
currentColor = memDC.GetPixel(x, y);//得到当前象素颜色
//如果当前色是透明颜色,就将该像素所在位置从窗体区域中去除
if (currentColor == TransColor)
{
currentRgn.CreateRectRgn(x, y, x + 1, y + 1);//创建区域
mainRgn.CombineRgn(&mainRgn, ¤tRgn, RGN_XOR);//去除相互重叠的区域
currentRgn.DeleteObject();//删除区域对象
}
else
{
//非透明色,想取最适合区域大小,还未实现
/* if (minX == 0 || minX > x)
{
minX = x;
}
if (minY == 0 || minY > y)
{
minY = y;
}
if (MaxX == rc.Width() || MaxX < x)
{
MaxX = x;
}
if (MaxY == rc.Height() || MaxY < y)
{
MaxY = y;
}
*/
}
}
}
MoveWindow(minX,minY,MaxX - minX,MaxY - minY,TRUE);
// mainRgn.OffsetRgn(-minX,-minY);
SetWindowRgn((HRGN)mainRgn, TRUE);//设置窗体为区域的形状
GetClientRect(&rc);
memDC.SelectObject(pOldMemBmp);
cBitmap.Detach();
memDC.DeleteDC();
ReleaseDC(pDC);
mainRgn.DeleteObject();
currentRgn.DeleteObject();//删除区域对象
}
void CLS_DlgBaseLayered::CreateRgnFromPic( CString _cstrPic )
{
if (!m_pImage)
{
m_pImage = new CImage;
}
else
{
m_pImage->Destroy();
}
m_pImage->Load(_cstrPic);
if (m_pImage->IsNull())
{
AfxMessageBox("请正确选择图象文件");
return;
}
COLORREF TransColor=RGB(1,0,0);//透明色
CBitmap cBitmap;
cBitmap.Attach(m_pImage->operator HBITMAP());//加载描述窗口形状的BMP图片
CDC* pDC=this->GetDC();
CDC memDC;
memDC.CreateCompatibleDC(pDC);//创建与传入DC兼容的临时DC
CBitmap *pOldMemBmp=NULL;
pOldMemBmp=memDC.SelectObject(&cBitmap);//将位图选入临时DC,方便对图片在控件环境中进行操作
CRgn wndRgn;
wndRgn.CreateRectRgn(0,0,0,0);//创建总的窗体区域,初始region为0
BITMAP bit;
cBitmap.GetBitmap (&bit);//取得位图参数,这里要用到位图的长和宽
int y;
TransColor=memDC.GetPixel(0,0);
CRgn rgnTemp; //保存临时region
for(y=0;y<=bit.bmHeight ;y++)
{
int iX = 0;
do
{
//跳过透明色找到下一个非透明色的点.
while (iX <= bit.bmWidth && memDC.GetPixel(iX, y) != TransColor)
iX++;
//记住这个起始点
int iLeftX = iX;
//寻找下个透明色的点
while (iX <= bit.bmWidth && memDC.GetPixel(iX, y) == TransColor)
++iX;
//创建一个包含起点与重点间高为1像素的临时“region”
rgnTemp.CreateRectRgn(iLeftX, y, iX, y+1);
//合并到主"region".
wndRgn.CombineRgn(&wndRgn, &rgnTemp, RGN_OR);
//删除临时"region",否则下次创建时和出错
rgnTemp.DeleteObject();
}while(iX
SetWindowRgn(wndRgn,TRUE);
memDC.SelectObject(pOldMemBmp);
memDC.DeleteDC();
cBitmap.Detach();
ReleaseDC(pDC);
wndRgn.DeleteObject();
rgnTemp.DeleteObject();
}
void CLS_DlgBaseLayered::SetMovable( bool _blCanMove /*= true*/ )
{
m_blCanMove = _blCanMove;
}
void CLS_DlgBaseLayered::OnLButtonDown(UINT nFlags, CPoint point)
{
if (m_blCanMove)
{
PostMessage( WM_SYSCOMMAND, SC_MOVE | HTCAPTION, 0);
return;
}
CDialog::OnLButtonDown(nFlags, point);
}
BOOL CLS_DlgBaseLayered::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
{
if (m_blCanMove && m_hCursor != NULL)
{
::SetCursor(m_hCursor);
return TRUE;
}
return CDialog::OnSetCursor(pWnd, nHitTest, message);
}
void CLS_DlgBaseLayered::OnBnClickedOk(){}
void CLS_DlgBaseLayered::OnBnClickedCancel(){}