在工作中遇到一个要实现动画按钮的问题,在网上搜索了一圈,也没有找到比较合适的解决方法。于是就自己花点时间写了一个。现在把实现方法贡献给大家,希望您有用。
实现方式为定义一个类“
CButtonUIEx
”,该类继承于“
CButtonUI
”。动画效果是用定时器来实现的,所以定义了两个定时器:一个用来播放鼠标进入动画,一个用于鼠标离开播放,其实就是逆序播放一遍。
#ifndef __UIBUTTONEX_H__
#define __UIBUTTONEX_H__
#pragma once
#define EVENT_ANIMA_ENTER_TIMERID UIMSG_USER+100 //鼠标进入按钮TimerID
#define EVENT_ANIMA_LEAVE_TIMERID UIMSG_USER+101 //鼠标离开按钮TimerID
class CButtonUIEx : public CButtonUI
{}
然后就是定义一个vector用于存放图片路径以及一个传入图片的接口。
.h文件
void SetAnimationImages(vector<DuiLib::CDuiString>);
vector<DuiLib::CDuiString> vecAnimation;
UINT m_nFrameCount; // 图片总帧数
UINT m_nFramePosition; // 当前放到第几帧
UINT m_nTimerSize; // 帧与帧之间间隔时间
BOOL m_bLeaveFlag;
.cpp文件
void CButtonUIEx::SetAnimationImages(vector<DuiLib::CDuiString> vecList)
{
vecAnimation = vecList;
m_nFrameCount = vecList.size();
}
这里是鼠标进入后的定时器TIMER以及帧处理方法
void CButtonUIEx::OnTimer(UINT_PTR idEvent)
{
if (idEvent != EVENT_ANIMA_ENTER_TIMERID)
return;
m_pManager->KillTimer(this, EVENT_ANIMA_ENTER_TIMERID);
this->Invalidate();
m_nFramePosition++;
m_pManager->SetTimer(this, EVENT_ANIMA_ENTER_TIMERID, m_nTimerSize);
}
void CButtonUIEx::DrawFrame(HDC hDC)
{
if (NULL == hDC || vecAnimation.size() == 0 || m_nFramePosition >= m_nFrameCount)
return;
DrawImage(hDC, (LPCTSTR)vecAnimation[m_nFramePosition]);
if (m_nFramePosition + 1 == m_nFrameCount)
{
m_pManager->KillTimer(this, EVENT_ANIMA_ENTER_TIMERID);
DrawImage(hDC, (LPCTSTR)vecAnimation[m_nFramePosition]);
this->Invalidate();
}
}
然后是鼠标离开定时器以及帧处理方法
void CButtonUIEx::OnLeaveTimer(UINT_PTR idEvent)
{
if (idEvent != EVENT_ANIMA_LEAVE_TIMERID)
return;
m_pManager->KillTimer(this, EVENT_ANIMA_LEAVE_TIMERID);
m_pManager->KillTimer(this, EVENT_ANIMA_ENTER_TIMERID);
this->Invalidate();
m_nFramePosition--;
m_pManager->SetTimer(this, EVENT_ANIMA_LEAVE_TIMERID, m_nTimerSize);
}
void CButtonUIEx::DrawLeaveFrame(HDC hDC)
{
if (NULL == hDC || vecAnimation.size() == 0)
return;
DrawImage(hDC, (LPCTSTR)vecAnimation[m_nFramePosition]);
if (m_nFramePosition == 0)
{
m_pManager->KillTimer(this, EVENT_ANIMA_LEAVE_TIMERID);
DrawImage(hDC, (LPCTSTR)vecAnimation[m_nFramePosition]);
this->Invalidate();
m_bLeaveFlag = false;
m_bNormalFlag = true;
}
}
第一次引发timer是在HOT事件中,所以重写了
PaintStatusImage方法。
void CButtonUIEx::PaintStatusImage(HDC hDC)
{
if (IsFocused()) m_uButtonState |= UISTATE_FOCUSED;
else m_uButtonState &= ~UISTATE_FOCUSED;
if (!IsEnabled()) m_uButtonState |= UISTATE_DISABLED;
else m_uButtonState &= ~UISTATE_DISABLED;
if (!::IsWindowEnabled(m_pManager->GetPaintWindow())) {
m_uButtonState &= UISTATE_DISABLED;
}
if ((m_uButtonState & UISTATE_DISABLED) != 0) {
if (!m_sDisabledImage.IsEmpty())
{
if (!DrawImage(hDC, (LPCTSTR)m_sDisabledImage)) m_sDisabledImage.Empty();
else goto Label_ForeImage;
}
}
else if ((m_uButtonState & UISTATE_PUSHED) != 0) {
if (!m_sPushedImage.IsEmpty()) {
if (!DrawImage(hDC, (LPCTSTR)m_sPushedImage)){
m_sPushedImage.Empty();
}
if (!m_sPushedForeImage.IsEmpty())
{
if (!DrawImage(hDC, (LPCTSTR)m_sPushedForeImage))
m_sPushedForeImage.Empty();
return;
}
else goto Label_ForeImage;
}
else if (m_dwPushedBkColor != 0) {
CRenderEngine::DrawColor(hDC, m_rcPaint, GetAdjustColor(m_dwPushedBkColor));
return;
}
}
else if ((m_uButtonState & UISTATE_HOT) != 0) {
if (!m_sHotImage.IsEmpty())
{
if (!DrawImage(hDC, (LPCTSTR)m_sHotImage))
{
m_sHotImage.Empty();
}
if (!m_sHotForeImage.IsEmpty())
{
if (!DrawImage(hDC, (LPCTSTR)m_sHotForeImage))
m_sHotForeImage.Empty();
return;
}
else goto Label_ForeImage;
}
else if (m_nFrameCount != 0)
{
m_pManager->SetTimer(this, EVENT_ANIMA_ENTER_TIMERID, m_nTimerSize); //主要是这一行。开启定时器
}
else if (m_dwHotBkColor != 0) {
CRenderEngine::DrawColor(hDC, m_rcPaint, GetAdjustColor(m_dwHotBkColor));
return;
}
}
else if ((m_uButtonState & UISTATE_FOCUSED) != 0) {
if (!m_sFocusedImage.IsEmpty()) {
if (!DrawImage(hDC, (LPCTSTR)m_sFocusedImage)) m_sFocusedImage.Empty();
else goto Label_ForeImage;
}
}
if (!m_sNormalImage.IsEmpty()) {
if (!DrawImage(hDC, (LPCTSTR)m_sNormalImage)) m_sNormalImage.Empty();
else goto Label_ForeImage;
}
if (!m_sForeImage.IsEmpty())
goto Label_ForeImage;
return;
Label_ForeImage:
if (!m_sForeImage.IsEmpty()) {
if (!DrawImage(hDC, (LPCTSTR)m_sForeImage)) m_sForeImage.Empty();
}
}
重新DoEvent事件。timer在这里响应
void CButtonUIEx::DoEvent(TEventUI& event)
{
CButtonUI::DoEvent(event);
if (event.Type == UIEVENT_MOUSELEAVE)
{
if (IsEnabled()) {
m_uButtonState &= ~UISTATE_HOT;
Invalidate();
if (m_pManager->KillTimer(this, EVENT_ANIMA_ENTER_TIMERID))
{
m_bLeaveFlag = true;
m_pManager->SetTimer(this, EVENT_ANIMA_LEAVE_TIMERID, m_nTimerSize);
}
}
}
if (event.Type == UIEVENT_TIMER)
{
if ((UINT_PTR)event.wParam == EVENT_ANIMA_ENTER_TIMERID)
OnTimer((UINT_PTR)event.wParam);
else if ((UINT_PTR)event.wParam == EVENT_ANIMA_LEAVE_TIMERID)
OnLeaveTimer((UINT_PTR)event.wParam);
}
}
至此。动画按钮完成,看下效果吧