同往常一样,先放一章效果图,这鸭子是会飞的哦。
效果类似常见的QQ宠物、360精灵之类的。
不说废话了,还是说重点。
==================================================
要实现这种效果,我的第一想法便是通过SetWindowRGN设置不规则窗体,然后更新。
显然,这样是最容易想到的,但是也不由的有点担心效率,最终我也通过这种方式,实现了一个,
正如担心的一样,每秒6帧的速度偶尔会出现闪烁(当然我的本本可能不是很给力- -。)。
这种方式就是通过载入的位图,获取每个像素点,并生成相应的HRGN,每帧动画一个。
然后通过计时器切换,由于效果不是很好,在此就不贴代码了。
既然不能通过SetWindowRGN,那还能怎么做呢?其实windows自身已经给了我们一个
处理这种位图窗口的API,而且还可以实现透明,一说到透明很多人都应该知道是那个API了。
Syntax
BOOL SetLayeredWindowAttributes( HWND hwnd,
COLORREF crKey,
BYTE bAlpha,
DWORD dwFlags
);
Parameters
hwnd
[in] Handle to the layered window. A layered window is created by specifying WS_EX_LAYERED when creating the window with the CreateWindowEx function or by setting WS_EX_LAYERED via SetWindowLong after the window has been created.
crKey
[in] COLORREF structure that specifies the transparency color key to be used when composing the layered window. All pixels painted by the window in this color will be transparent. To generate a COLORREF, use the RGB macro.
bAlpha
[in] Alpha value used to describe the opacity of the layered window. Similar to the SourceConstantAlpha member of the BLENDFUNCTION structure. When bAlpha is 0, the window is completely transparent. When bAlpha is 255, the window is opaque.
dwFlags
[in] Specifies an action to take. This parameter can be one or more of the following values.
LWA_COLORKEY
Use crKey as the transparency color.
LWA_ALPHA
Use bAlpha to determine the opacity of the layered window.
Return Value
If the function succeeds, the return value is nonzero.
If the function fails, the return value is zero. To get extended error information, call GetLastError.
其实这个函数在以前也经常用到,但主要是用它来实现透明,根本没想到它还可以实现不规则窗体。
看了MSDN你应该知道了吧,其实通过设置第二个颜色属性便可过滤掉窗体中指定的某种颜色,达到
不规则窗体的效果。
设置透明色的代码如下:再此将白色设置为透明。
HINSTANCE hInstance=(HINSTANCE)LoadLibrary("user32.dll");
if (hInstance)
{
typedef BOOL(WINAPI *pFun)(HWND,COLORREF,BYTE,DWORD);
pFun fun = NULL;
fun=(pFun)GetProcAddress(hInstance, "SetLayeredWindowAttributes");
SetWindowLong(GWL_EXSTYLE, GetWindowLong(GWL_EXSTYLE) | 0x80000);
if (fun)
{
fun(hWnd, RGB(255, 255, 255), 0, 0x1);
}
FreeLibrary(hInstance);
}
知道如何处理不规则窗体后剩下的就简单了,在此我用的一半游戏中的(4*4)行走图做的。
只需要在绘制的时候通过改变绘制区域坐标来控制显示的位置达到动画的效果。
其中m_nX,m_nY分别是横向帧数 和 竖向的帧数 在此为 4 * 4
void OnPaint(CDCHandle /**//*dc*/)
{
CPaintDC dc(*this);
CDC bmpDC;
CBitmapHandle bmpOld;
CRect rtClient;
GetClientRect(&rtClient);
bmpDC.CreateCompatibleDC(dc);
bmpOld = bmpDC.SelectBitmap(m_bmpBox);
int nSubX = m_nWidth / m_nX;
int nSubY = m_nHeight / m_nY;
dc.BitBlt(0, 0, nSubX, nSubY, bmpDC, m_nCurX * nSubX,
m_nCurY * nSubY, SRCCOPY);
bmpDC.SelectBitmap(bmpOld);
}
剩下就是一些辅助的功能了:m_nCurX m_nCurY 分别只是当前横向第几帧 和 纵向的第几帧
/**//**
* 实现移动窗口
*/
UINT OnNcHitTest(CPoint point)
{
return HTCAPTION;
}
/**//**
* 更新动画
*/
void OnTimer(UINT_PTR nIDEvent)
{
if (nIDEvent == ANIMA_TIMER)
{
m_nCurX = (++m_nCurX) % m_nX;
RedrawWindow();
}
}
/**//**
* 改变方向
*/
void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
switch (nChar)
{
case VK_LEFT: m_nCurY = 1; break;
case VK_RIGHT: m_nCurY = 2; break;
case VK_UP: m_nCurY = 3; break;
case VK_DOWN: m_nCurY = 0; break;
case VK_ESCAPE:OnClose();break;
}
}
好了,结束,虽然没啥技术含量,但也可以打发下无聊的时间。
以后有好玩的东西我也会更新在此。