Chapter 136 · XUI 基础控件

Toggle 开关

Toggle 滑动开关控件,带轨道和滑块动画,支持内部文本、自定义尺寸与颜色。

136

概念

Toggle 是滑动开关,适合二元设置:
• 轨道(Track)+ 滑块(Thumb)结构
• 内部文本:ON/OFF 显示在轨道内
• 外部文本:开关旁的说明标签
• 支持自定义 Surface 替代默认滑块

API 速查

函数说明
int xuiToggleCreate(xui_context pCtx, xui_widget* ppW, const xui_toggle_desc_t* pDesc)创建开关
int xuiToggleSetChange(xui_widget pW, xui_toggle_change_proc onChange, void* pUser)变化回调
int xuiToggleSetChecked(xui_widget pW, int bChecked)设置开关状态
int xuiToggleGetChecked(xui_widget pW)获取状态
int xuiToggleSetText(xui_widget pW, const char* sText)外部文本
int xuiToggleSetInnerText(xui_widget pW, const char* sUnchk, const char* sChk)内部文本
int xuiToggleSetTrackSize(xui_widget pW, float fW, float fH)轨道尺寸
int xuiToggleSetThumbSize(xui_widget pW, float fSize)滑块大小
int xuiToggleSetColors(xui_widget pW, uint32_t iAccent, uint32_t iTrack, uint32_t iHoverTrack, uint32_t iFocus)颜色
int xuiToggleSetGap(xui_widget pW, float fGap)开关与文字间距

编译本章示例

gcc -O2 -I. -o ch136.exe ch136_main.c src\xui_*.c build\xge.lib -lm -lws2_32 -liphlpapi -lgdi32 -luser32 -lshell32 -lopengl32 -lole32 -lwinmm -lavrt
.\ch136.exe

示例:声音开关

static void OnSoundToggle(xui_widget pW,
    int bChecked, void* pUser)
{
    xgeAudioSetVolume(bChecked ? 1.0f : 0.0f);
}

xui_toggle_desc_t desc = { 0 };
desc.sText = "声音";
desc.bChecked = 1;

xui_widget pToggle;
xuiToggleCreate(pCtx, &pToggle, &desc);
xuiToggleSetChange(pToggle, OnSoundToggle, NULL);

// 轨道 40x20,滑块 16
xuiToggleSetTrackSize(pToggle, 40.0f, 20.0f);
xuiToggleSetThumbSize(pToggle, 16.0f);

// 内部 ON/OFF 文本
xuiToggleSetInnerText(pToggle, "OFF", "ON");

// 绿色强调色
xuiToggleSetColors(pToggle,
    0xFF22C55E, 0xFF4B5563,
    0xFF6B7280, 0x4022C55E);

xuiWidgetAddChild(pSettingsPanel, pToggle);

完整代码

将以下代码保存为 ch136_main.c,编译后运行即可看到开关切换效果:

#include "xge.h"
#include "xui.h"
#include <stdio.h>

static xui_context g_pCtx;

static void OnSoundToggle(xui_widget pW,
    int bChecked, void* pUser) {
    (void)pW; (void)pUser;
    printf("Sound: %s\n",
        bChecked ? "ON" : "OFF");
}

static int onFrame(void* pUser) {
    (void)pUser;
    xgeClear(0x081114FF);
    float mx, my;
    xgeMouseGet(&mx, &my);
    xuiInputPointerMove(g_pCtx, mx, my, 0);
    if (xgeMouseDown(XGE_MOUSE_LEFT))
        xuiInputPointerDown(g_pCtx, mx, my, 0, 1);
    if (!xgeMouseDown(XGE_MOUSE_LEFT) /* 释放边沿建议改用事件 */)
        xuiInputPointerUp(g_pCtx, mx, my, 0, 0);
    xuiUpdate(g_pCtx, xgeGetDelta());
    xuiLayout(g_pCtx);
    xuiRender(g_pCtx, NULL, NULL, 0);
    return XGE_OK;
}

int main(void) {
    xge_desc_t d = {0};
    d.iWidth  = 800;
    d.iHeight = 600;
    d.sTitle  = "ch136 - Toggle";
    d.iFlags  = XGE_INIT_VSYNC;
    xgeInit(&d);

    xuiCreate(&g_pCtx);
    extern const xui_proxy_t tXgeProxy;
    xui_proxy_t tXgeProxy = xuiProxyXge();
xuiSetProxy(g_pCtx, &tXgeProxy);
    xuiSetViewportSize(g_pCtx, 800, 600);

    // 创建开关
    xui_toggle_desc_t desc = { 0 };
    desc.sText = "Sound";
    desc.bChecked = 1;
    xui_widget pToggle;
    xuiToggleCreate(g_pCtx, &pToggle, &desc);
    xuiToggleSetChange(pToggle,
        OnSoundToggle, NULL);
    xuiToggleSetTrackSize(pToggle, 40.0f, 20.0f);
    xuiToggleSetThumbSize(pToggle, 16.0f);
    xuiToggleSetInnerText(pToggle, "OFF", "ON");
    xuiToggleSetColors(pToggle,
        0xFF22C55E, 0xFF4B5563,
        0xFF6B7280, 0x4022C55E);
    xuiWidgetSetRect(pToggle,
        (xui_rect_t){ 300, 280, 200, 30 });

    xgeRun(onFrame, NULL);

    xuiDestroy(g_pCtx);
    xgeUnit();
    return 0;
}

代码讲解

  • xuiToggleCreate:创建开关控件,desc 设置初始文本和状态。
  • xuiToggleSetTrackSize:设置轨道宽高,决定开关整体尺寸。
  • xuiToggleSetInnerText:轨道内显示 ON/OFF 文本。
  • xuiToggleSetColors:设置强调色/轨道色/悬停色/焦点色。
  • 内置动画:滑块切换时自动平滑过渡,无需手动实现。

要点与陷阱

  • InnerText:显示在轨道内部,需轨道足够宽。
  • TrackSize:轨道宽高决定开关整体大小。
  • ThumbSize:滑块直径,应小于轨道高度。
  • 动画:内置平滑过渡,无需手动实现。

进阶练习

  1. 带图标的滑块:用 IndicatorSurface 替换为自定义图片。
  2. 设置面板:多个 Toggle 控制音频/视频/输入选项。
Toggle 开关效果
图:Toggle 开关渲染效果