SDL3_API分类参考_系统托盘(CategoryTray)

2026-3-7 / 0 评论 / 2 阅读

系统托盘子系统(CategoryTray)

SDL 提供了系统托盘(Windows 中更准确的称呼是「通知区域」)操作接口,在支持该功能的平台上(Windows/macOS/Linux 主流桌面环境),SDL 应用可创建托盘图标、添加子菜单、复选框、可点击菜单项,并注册回调函数响应用户的点击操作。

系统托盘功能让应用在后台运行时仍能与用户交互,是桌面应用的常用特性(如后台服务、工具类软件)。


函数

  • SDL_CreateTray:创建基础系统托盘实例,返回 SDL_Tray 句柄(失败返回 NULL,需初始化视频子系统)
  • SDL_CreateTrayWithProperties:创建带自定义属性的托盘实例(支持图标、提示文本等初始配置)
  • SDL_DestroyTray:销毁托盘实例,移除系统托盘中的图标和菜单,释放所有关联资源
  • SDL_SetTrayIcon:设置托盘图标(传入 SDL_Surface 或 SDL_Texture 类型的图标资源)
  • SDL_SetTrayTooltip:设置托盘图标的悬浮提示文本(鼠标悬停时显示)
  • SDL_CreateTrayMenu:创建托盘菜单容器,用于存放菜单项
  • SDL_CreateTraySubmenu:创建子菜单(嵌套在主菜单中的二级菜单)
  • SDL_InsertTrayEntryAt:在指定位置插入托盘菜单项(支持普通项、复选框、分隔符等)
  • SDL_RemoveTrayEntry:移除指定的托盘菜单项
  • SDL_SetTrayEntryLabel:设置菜单项的显示文本
  • SDL_SetTrayEntryChecked:设置复选框类型菜单项的选中状态
  • SDL_GetTrayEntryChecked:获取复选框菜单项的选中状态
  • SDL_SetTrayEntryEnabled:设置菜单项是否可用(禁用时灰显,无法点击)
  • SDL_GetTrayEntryEnabled:获取菜单项的启用状态
  • SDL_GetTrayEntryLabel:获取菜单项的显示文本
  • SDL_SetTrayEntryCallback:为菜单项注册点击回调函数
  • SDL_ClickTrayEntry:手动触发菜单项的点击事件(模拟用户操作)
  • SDL_GetTrayEntries:获取指定菜单下的所有菜单项列表
  • SDL_GetTrayEntryParent:获取菜单项所属的父菜单/父托盘
  • SDL_GetTrayMenu:获取托盘实例关联的主菜单
  • SDL_GetTraySubmenu:获取菜单项关联的子菜单(若有)
  • SDL_GetTrayMenuParentEntry:获取子菜单所属的父菜单项
  • SDL_GetTrayMenuParentTray:获取菜单所属的父托盘实例
  • SDL_UpdateTrays:更新所有托盘实例的显示(修改菜单/图标后需调用)

数据类型

  • SDL_Tray:系统托盘实例句柄类型,封装平台相关的托盘资源(如 Windows 的 NOTIFYICONDATA)
  • SDL_TrayMenu:托盘菜单容器类型,管理多个菜单项的集合
  • SDL_TrayEntry:托盘菜单项类型,代表单个可点击/可选的菜单元素(普通项、复选框、子菜单、分隔符)
  • SDL_TrayEntryFlags:菜单项标志类型,标识菜单项类型(普通项、复选框、分隔符、子菜单等)
  • SDL_TrayCallback:菜单项通用回调函数类型,响应菜单项的状态变更
  • SDL_TrayClickCallback:菜单项点击回调函数类型,用户点击菜单项时触发

结构体

  • (无)

枚举

  • (无)

  • (无)

FreeBASIC 示例代码

' 引入 SDL 相关声明(需确保 FreeBASIC 已链接 SDL3 库)
#Include "SDL.bi"

' 补充类型/函数声明(FreeBASIC 绑定可能缺失)
Type SDL_Tray As Any Ptr
Type SDL_TrayMenu As Any Ptr
Type SDL_TrayEntry As Any Ptr
Type SDL_TrayEntryFlags As Uint32

' 菜单项类型标志(示例值,实际 SDL 定义以官方为准)
Const SDL_TRAYENTRY_NORMAL = 0          ' 普通菜单项
Const SDL_TRAYENTRY_CHECKBOX = 1 Shl 0  ' 复选框菜单项
Const SDL_TRAYENTRY_SEPARATOR = 1 Shl 1 ' 分隔符
Const SDL_TRAYENTRY_SUBMENU = 1 Shl 2   ' 子菜单入口

' 回调函数类型定义
Type SDL_TrayClickCallback As Sub( _
    ByVal entry As SDL_TrayEntry, _
    ByVal userdata As Any Ptr _
)

' 核心函数声明
Declare Function SDL_CreateTray CDecl () As SDL_Tray
Declare Sub SDL_DestroyTray CDecl (ByVal tray As SDL_Tray)
Declare Function SDL_SetTrayIcon CDecl (ByVal tray As SDL_Tray, ByVal icon As SDL_Surface Ptr) As SDL_bool
Declare Function SDL_SetTrayTooltip CDecl (ByVal tray As SDL_Tray, ByVal tooltip As ZString Ptr) As SDL_bool
Declare Function SDL_CreateTrayMenu CDecl () As SDL_TrayMenu
Declare Function SDL_InsertTrayEntryAt CDecl ( _
    ByVal menu As SDL_TrayMenu, _
    ByVal index As Integer, _
    ByVal flags As SDL_TrayEntryFlags, _
    ByVal label As ZString Ptr, _
    ByVal userdata As Any Ptr _
) As SDL_TrayEntry
Declare Function SDL_CreateTraySubmenu CDecl (ByVal entry As SDL_TrayEntry) As SDL_TrayMenu
Declare Sub SDL_SetTrayEntryCallback CDecl (ByVal entry As SDL_TrayEntry, ByVal callback As SDL_TrayClickCallback)
Declare Sub SDL_SetTrayEntryChecked CDecl (ByVal entry As SDL_TrayEntry, ByVal checked As SDL_bool)
Declare Function SDL_GetTrayEntryChecked CDecl (ByVal entry As SDL_TrayEntry) As SDL_bool
Declare Sub SDL_SetTrayEntryEnabled CDecl (ByVal entry As SDL_TrayEntry, ByVal enabled As SDL_bool)
Declare Function SDL_GetTrayMenu CDecl (ByVal tray As SDL_Tray) As SDL_TrayMenu
Declare Sub SDL_SetTrayMenu CDecl (ByVal tray As SDL_Tray, ByVal menu As SDL_TrayMenu)
Declare Sub SDL_UpdateTrays CDecl ()

' 全局托盘实例
Dim Shared As SDL_Tray g_tray = NULL
' 全局退出标志
Dim Shared As SDL_bool g_quit = SDL_FALSE

' 菜单项点击回调:显示主窗口
Sub ShowWindowCallback(ByVal entry As SDL_TrayEntry, ByVal userdata As Any Ptr)
    SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "【托盘回调】用户点击了「显示窗口」")
    ' 模拟显示主窗口逻辑
    SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "→ 显示应用主窗口")
End Sub

' 菜单项点击回调:切换静音状态
Sub ToggleMuteCallback(ByVal entry As SDL_TrayEntry, ByVal userdata As Any Ptr)
    SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "【托盘回调】用户点击了「静音模式」")
    ' 切换复选框状态
    Dim As SDL_bool checked = SDL_GetTrayEntryChecked(entry)
    SDL_SetTrayEntryChecked(entry, Not checked)
    ' 刷新托盘显示
    SDL_UpdateTrays()
    ' 模拟静音逻辑
    If (Not checked) Then
        SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "→ 开启静音模式")
    Else
        SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "→ 关闭静音模式")
    End If
End Sub

' 菜单项点击回调:退出应用
Sub ExitAppCallback(ByVal entry As SDL_TrayEntry, ByVal userdata As Any Ptr)
    SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "【托盘回调】用户点击了「退出」")
    g_quit = SDL_TRUE
End Sub

' 创建系统托盘及菜单
Function CreateSystemTray() As SDL_bool
    ' 1. 创建托盘实例
    g_tray = SDL_CreateTray()
    If (g_tray = NULL) Then
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "创建托盘失败:%s", SDL_GetError())
        Return SDL_FALSE
    End If

    ' 2. 设置托盘提示文本(鼠标悬浮显示)
    If (SDL_SetTrayTooltip(g_tray, StrPtr("SDL 托盘示例")) = SDL_FALSE) Then
        SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "设置托盘提示失败:%s", SDL_GetError())
    End If

    ' 3. 创建托盘主菜单
    Dim As SDL_TrayMenu Ptr mainMenu = SDL_CreateTrayMenu()
    If (mainMenu = NULL) Then
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "创建主菜单失败:%s", SDL_GetError())
        SDL_DestroyTray(g_tray)
        Return SDL_FALSE
    End If

    ' 4. 添加菜单项:显示窗口(普通项)
    Dim As SDL_TrayEntry Ptr showWindowEntry = SDL_InsertTrayEntryAt( _
        mainMenu, _
        0, _
        SDL_TRAYENTRY_NORMAL, _
        StrPtr("显示窗口"), _
        NULL _
    )
    If (showWindowEntry <> NULL) Then
        SDL_SetTrayEntryCallback(showWindowEntry, @ShowWindowCallback)
    End If

    ' 5. 添加菜单项:分隔符
    SDL_InsertTrayEntryAt( _
        mainMenu, _
        1, _
        SDL_TRAYENTRY_SEPARATOR, _
        NULL, _
        NULL _
    )

    ' 6. 添加菜单项:静音模式(复选框)
    Dim As SDL_TrayEntry Ptr muteEntry = SDL_InsertTrayEntryAt( _
        mainMenu, _
        2, _
        SDL_TRAYENTRY_CHECKBOX, _
        StrPtr("静音模式"), _
        NULL _
    )
    If (muteEntry <> NULL) Then
        SDL_SetTrayEntryChecked(muteEntry, SDL_FALSE) ' 默认未选中
        SDL_SetTrayEntryCallback(muteEntry, @ToggleMuteCallback)
    End If

    ' 7. 添加菜单项:退出(普通项)
    Dim As SDL_TrayEntry Ptr exitEntry = SDL_InsertTrayEntryAt( _
        mainMenu, _
        3, _
        SDL_TRAYENTRY_NORMAL, _
        StrPtr("退出"), _
        NULL _
    )
    If (exitEntry <> NULL) Then
        SDL_SetTrayEntryCallback(exitEntry, @ExitAppCallback)
    End If

    ' 8. 将菜单关联到托盘
    SDL_SetTrayMenu(g_tray, mainMenu)

    ' 9. 更新托盘显示
    SDL_UpdateTrays()

    SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "系统托盘创建成功")
    Return SDL_TRUE
End Function

' 主程序
Sub Main()
    ' 初始化 SDL(必须初始化视频子系统)
    If (SDL_Init(SDL_INIT_VIDEO) < 0) Then
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL 初始化失败:%s", SDL_GetError())
        Exit Sub
    End If

    ' 创建系统托盘
    If (CreateSystemTray() = SDL_FALSE) Then
        SDL_Quit()
        Exit Sub
    End If

    ' 主事件循环(保持应用运行,等待用户操作)
    SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "应用后台运行中,点击托盘「退出」结束程序...")
    While (g_quit = SDL_FALSE)
        Dim As SDL_Event evt
        ' 处理 SDL 事件(托盘点击事件需通过事件循环分发)
        While (SDL_PollEvent(@evt))
            If (evt.type = SDL_QUIT) Then
                g_quit = SDL_TRUE
            End If
        Wend
        SDL_Delay(100) ' 降低CPU占用
    Wend

    ' 销毁托盘实例
    If (g_tray <> NULL) Then
        SDL_DestroyTray(g_tray)
        SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "系统托盘已销毁")
    End If

    ' 清理 SDL
    SDL_Quit()
    SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "程序正常退出")
End Sub

' 运行主程序
Main()

核心知识点补充

  1. 关键前置条件

    • 必须初始化 SDL 视频子系统(SDL_Init(SDL_INIT_VIDEO)),托盘依赖窗口系统资源;
    • 托盘创建后需调用 SDL_UpdateTrays() 才能生效(修改菜单/图标后也需调用);
    • 应用需保持事件循环运行,否则无法响应托盘点击事件。
  2. 菜单项类型说明 标志常量 菜单项类型 用途
    SDL_TRAYENTRY_NORMAL 普通菜单项 点击触发回调(如「显示窗口」「退出」)
    SDL_TRAYENTRY_CHECKBOX 复选框项 可选中/取消选中(如「静音模式」)
    SDL_TRAYENTRY_SEPARATOR 分隔符 视觉分隔不同功能的菜单项
    SDL_TRAYENTRY_SUBMENU 子菜单入口 点击展开二级菜单
  3. 平台兼容性 平台 支持情况 特殊说明
    Windows 完全支持(所有功能) 托盘图标显示在通知区域,支持所有菜单项类型
    macOS 完全支持(所有功能) 托盘图标显示在菜单栏右侧,样式适配macOS
    Linux 大部分支持(依赖桌面环境) GNOME/KDE 支持良好,轻量桌面可能部分功能失效
    移动平台 不支持 无系统托盘概念
  4. 资源管理注意

    • 必须调用 SDL_DestroyTray() 销毁托盘实例,否则会导致资源泄漏(尤其 Windows 平台);
    • 菜单项的用户数据(userdata)需自行管理生命周期,避免悬空指针;
    • 托盘图标建议使用 16x16/32x32 尺寸的 PNG/BMP,保证不同 DPI 下显示清晰。

总结

  1. 核心优势

    • 跨平台统一的系统托盘接口,无需适配 Windows 的 Shell_NotifyIcon、macOS 的 NSStatusItem 等原生 API;
    • 支持丰富的菜单类型(普通项、复选框、子菜单、分隔符),满足桌面应用的交互需求;
    • 回调机制清晰,可精准响应用户对菜单项的点击操作;
    • 与 SDL 事件循环无缝集成,保证应用后台运行时的响应性。
  2. 使用建议

    • 托盘创建后需关联菜单才能显示右键菜单,空托盘仅显示图标无交互;
    • 复选框菜单项需手动调用 SDL_SetTrayEntryChecked() 切换状态,并调用 SDL_UpdateTrays() 刷新;
    • 退出应用前必须销毁托盘实例,避免残留托盘图标(Windows 平台易出现此问题);
    • 托盘图标建议提供多分辨率版本,适配不同系统的显示缩放比例。
  3. 关键点回顾

    • SDL_Tray 是托盘核心句柄,所有托盘操作均基于此;
    • 修改托盘菜单/图标后必须调用 SDL_UpdateTrays() 才能生效;
    • 菜单项点击回调需配合 SDL 事件循环才能触发,应用需保持事件循环运行;
    • 不同平台的托盘样式有差异,但接口行为一致,无需额外适配。

评论一下?

OωO
取消