跳转至

SOUI中的定时器

定时器是GUI编程中实现动画效果的重要工具。本文介绍SOUI框架中定时器的使用方法和注意事项。

定时器类型

SOUI框架提供了三种类型的定时器:

  1. SWND定时器(SWindow::SetTimer)
  2. 扩展定时器(SWindow::SetTimer2)
  3. 宿主窗口定时器(::SetTimer/CSimpleWnd::SetTimer)

SWND定时器

定时器ID结构

SOUI使用32位定时器ID,按位划分:

class SOUI_EXP STimerID
{
public:
    DWORD Swnd:24;        // 窗口句柄,最大支持16777215个窗口
    DWORD uTimerID:7;     // 定时器ID,支持0-127
    DWORD bSwndTimer:1;   // 标志位,1表示SWND定时器
};

创建定时器

// 创建一个ID为0-127的定时器
BOOL SWindow::SetTimer(char id, UINT uElapse);

销毁定时器

// 删除指定ID的定时器
void SWindow::KillTimer(char id);

响应定时器消息

// 在消息映射表中使用MSG_WM_TIMER_EX
SOUI_MSG_MAP_BEGIN()
    MSG_WM_TIMER_EX(OnTimer)  // 定时器消息
SOUI_MSG_MAP_END()

// 处理函数
void OnTimer(char cTimerID)
{
    // 处理定时器消息
}

扩展定时器(SetTimer2)

当需要使用32位定时器ID时,可以使用SetTimer2:

创建定时器

// 创建一个支持完整32位ID的定时器
BOOL SWindow::SetTimer2(UINT_PTR id, UINT uElapse);

销毁定时器

// 删除SetTimer2创建的定时器
void SWindow::KillTimer2(UINT_PTR id);

响应定时器消息

// 在消息映射表中使用MSG_WM_TIMER2
SOUI_MSG_MAP_BEGIN()
    MSG_WM_TIMER2(OnTimer2)  // Timer2消息
SOUI_MSG_MAP_END()

// 处理函数
void OnTimer2(UINT_PTR id)
{
    // 处理Timer2消息
}

宿主窗口定时器

在应用层可以直接使用Win32定时器:

创建定时器

// 使用Win32 API
::SetTimer(hwnd, timerID, interval, NULL);

// 或使用CSimpleWnd类方法
CSimpleWnd::SetTimer(UINT_PTR nIDEvent, UINT nElapse);

响应定时器消息

// 在宿主窗口消息映射中
void OnTimer(UINT_PTR idEvent)
{
    // 处理自己的定时器
    if(idEvent == myTimerID)
    {
        // 处理定时器逻辑
    }
    else
    {
        // 不是自己的定时器,交给基类处理
        SetMsgHandled(FALSE);
        // 或者调用基类
        // SHostWnd::OnTimer(idEvent);
    }
}

最佳实践

1. 选择合适的定时器类型

  • 控件开发时优先使用SWND定时器(SetTimer)
  • 需要32位ID时使用SetTimer2
  • 应用层可以直接使用Win32定时器

2. 定时器ID管理

  • SWND定时器ID范围:0-127
  • SetTimer2支持完整32位ID
  • Win32定时器ID最高位必须为0

3. 性能考虑

  • SetTimer效率最高
  • SetTimer2在KillTimer2时效率较低
  • 合理设置定时器间隔

4. 注意事项

  1. ID冲突避免
  2. 不同类型定时器ID要避免冲突
  3. 同一窗口的定时器ID要唯一

  4. 资源释放

  5. 窗口销毁前要清理定时器
  6. 使用完毕及时销毁定时器

  7. 消息处理

  8. 正确使用消息映射宏
  9. 注意消息传递链

使用示例

1. 动画效果实现

class SAnimationWindow : public SWindow
{
    void OnCreate()
    {
        // 创建动画定时器
        SetTimer(1, 16);  // 约60fps
    }

    void OnTimer(char cTimerID)
    {
        if(cTimerID == 1)
        {
            // 更新动画
            InvalidateRect(NULL);
        }
    }

    void OnDestroy()
    {
        // 清理定时器
        KillTimer(1);
    }

    SOUI_MSG_MAP_BEGIN()
        MSG_WM_TIMER_EX(OnTimer)
    SOUI_MSG_MAP_END()
};

2. 延时操作

void SMyWindow::DelayedOperation()
{
    // 设置一次性定时器
    SetTimer2(100, 1000);  // 1秒后执行
}

void SMyWindow::OnTimer2(UINT_PTR id)
{
    if(id == 100)
    {
        // 执行延时操作
        KillTimer2(100);  // 清理一次性定时器
    }
}