duilib动画按钮实现

时间:2022-07-29 19:27:28
在工作中遇到一个要实现动画按钮的问题,在网上搜索了一圈,也没有找到比较合适的解决方法。于是就自己花点时间写了一个。现在把实现方法贡献给大家,希望您有用。
实现方式为定义一个类“ 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);
    }
}
至此。动画按钮完成,看下效果吧
duilib动画按钮实现