Chapter 150 · XUI 容器与导航

Window 窗口

Window 可拖动/缩放的浮动窗口,支持标题栏按钮、折叠、最大化、层级管理、TopMost。

150

概念

Window 是 XUI 的浮动窗口控件:
• TitleBar:标题栏(图标 + 标题 + 折叠/最大化/关闭按钮)
• Client:客户区,承载内容控件
• 拖动:标题栏拖动或 DragAnywhere 全区域拖动
• 缩放:边缘/角落拖拽调整大小,可限制 ResizeEdges
• 层级:BringToFront 置顶,TopMost 始终最前

API 速查

函数说明
int xuiWindowCreate(xui_context pCtx, xui_widget* ppW, const xui_window_desc_t* pDesc)创建窗口
xui_widget xuiWindowGetClientWidget(xui_widget pW)获取客户区
int xuiWindowSetTitle(xui_widget pW, const char* sTitle)设置标题
int xuiWindowSetMovable(xui_widget pW, int bEnabled)允许拖动
int xuiWindowSetResizable(xui_widget pW, int bEnabled)允许缩放
int xuiWindowSetCollapsed(xui_widget pW, int bCollapsed)折叠
int xuiWindowSetMaximized(xui_widget pW, int bMaximized)最大化
int xuiWindowBringToFront(xui_widget pW)置前
int xuiWindowSetTopMost(xui_widget pW, int bTopMost)始终最前
int xuiWindowSetMinSize(xui_widget pW, float fW, float fH)最小尺寸
int xuiWindowSetChrome(xui_widget pW, float fTitleH, float fBorder, float fGrip, float fBtn)外观度量

编译本章示例

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

示例:工具窗口

xui_window_desc_t desc = { 0 };
desc.sTitle = "图层";

xui_widget pWin;
xuiWindowCreate(pCtx, &pWin, &desc);
/* 窗口位置由停靠/拖动决定 */
xuiWidgetSetRect(pWin, (xui_rect_t){0, 0, 280.0f, 360.0f});

xuiWindowSetMovable(pWin, 1);
xuiWindowSetResizable(pWin, 1);
xuiWindowSetMinSize(pWin, 200.0f, 150.0f);
xuiWindowSetShowMaximize(pWin, 0); // 隐藏最大化按钮

// 向客户区添加内容
xui_widget pClient = xuiWindowGetClientWidget(pWin);
xuiWindowAddChild(pWin, pLayerList);

xuiWindowSetClose(pWin, OnWinClose, NULL);
xuiWidgetAddChild(pRoot, pWin);

完整代码

将以下代码保存为 ch150_main.c,编译后运行即可看到可拖动窗口效果:

#include "xge.h"
#include "xui.h"

static xui_context g_pCtx;

static int onFrame(void* pUser) {
    (void)pUser;
    xgeClear(0x081114FF);
    float mx, my;
    xgeMouseGet(&mx, &my);
    xuiInputPointerMove(g_pCtx, mx, my);
    if (xgeMouseDown(XGE_MOUSE_LEFT))
        xuiInputPointerDown(g_pCtx, 0);
    else
        xuiInputPointerUp(g_pCtx, 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 = "ch150 - Window";
    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_widget pRoot;
    xuiWidgetCreate(g_pCtx, &pRoot);
    xuiWidgetSetLayoutType(pRoot, XUI_LAYOUT_MANUAL);
    xuiWidgetSetRect(pRoot, (xui_rect_t){0, 0, 800, 600});
    xuiSetRootWidget(g_pCtx, pRoot);

    /* 创建可拖动/缩放窗口 */
    xui_window_desc_t wd = { 0 };
    wd.sTitle = "图层面板";
    xui_widget pWin;
    xuiWindowCreate(g_pCtx, &pWin, &wd);
    /* 窗口位置由停靠/拖动决定 */
    xuiWidgetSetRect(pWin, (xui_rect_t){0, 0, 300, 350});
    xuiWindowSetMovable(pWin, 1);
    xuiWindowSetResizable(pWin, 1);
    xuiWindowSetMinSize(pWin, 200, 150);
    xuiWidgetAddChild(pRoot, pWin);

    /* 向客户区添加内容 */
    xui_label_desc_t lb = { 0 };
    lb.sText = "拖动标题栏移动窗口\n拖拽边缘调整大小";
    xui_widget pLb;
    xuiLabelCreate(g_pCtx, &pLb, &lb);
    xuiWindowAddChild(pWin, pLb);

    xgeRun(onFrame, NULL);
    xuiDestroy(g_pCtx);
    xgeUnit();
    return 0;
}

代码讲解

  • Manual 根容器:窗口需要绝对定位,根容器用 Manual 布局。
  • Movable/Resizable:启用标题栏拖动和边缘缩放。
  • MinSize:限制窗口最小尺寸,防止缩得太小。
  • WindowAddChild:子控件添加到客户区而非标题栏。

要点与陷阱

  • Collapsed:折叠后仅显示标题栏,客户区隐藏。
  • ResizeEdges:位掩码控制哪些边/角可拖拽缩放。
  • DragAnywhere:启用后窗口任意位置均可拖动(无标题栏模式)。
  • IsActive:当前焦点窗口高亮标题栏,非活动窗口变暗。
  • SetOpen(0):隐藏窗口但不销毁,可再次 SetOpen(1) 显示。

进阶练习

  1. 多窗口管理:创建多个 Window,点击时 BringToFront。
  2. 无标题栏窗口:ShowTitleBar(0) + DragAnywhere(1) 实现自定义拖动。
Window 窗口效果
图:Window 窗口渲染效果