You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

解决Nuklear中鼠标事件重复触发导致窗口抖动的问题

问题:Nuklear+SDL2窗口最小化按钮点击后持续抖动

我用C语言结合Nuklear和SDL2开发渲染器,给调试窗口添加NK_WINDOW_MINIMIZABLE标志后,点击右上角最小化按钮会触发大量SDL事件,导致窗口反复最小化/最大化,持续抖动。

渲染UI代码

void renderUI(){
    static struct nk_colorf color = {1.0f, 0.0f, 0.0f, 1.0f};
    
    if (nk_begin(ctx, "Debug Window", nk_rect(0, 0, 410, 500), NK_WINDOW_BORDER | NK_WINDOW_MOVABLE | NK_WINDOW_MINIMIZABLE)) {
        
        // Define row layout with two columns: label + value
        nk_layout_row_dynamic(ctx, 130, 2);
        // Display "Camera Position: "
        nk_label(ctx, "Camera Position:", NK_TEXT_LEFT);
        
        get_camera_position(&p);
        nk_labelf(ctx, NK_TEXT_LEFT, "(%.2f, %.2f, %.2f)", p[0], p[1], p[2]);

        nk_layout_row_dynamic(ctx, 130, 2);
        nk_label(ctx, "Light Colour:", NK_TEXT_LEFT);
        color = nk_color_picker(ctx, color, NK_RGBA); // RGB mode (or NK_RGBA for alpha)
        
        nk_layout_row_dynamic(ctx, 130, 2);
        nk_label(ctx,"Frame Rate: ",NK_TEXT_ALIGN_LEFT);
        nk_labelf(ctx, NK_TEXT_LEFT, "(%.2f)", fps);


        lightColor[0] = color.r;
        lightColor[1] = color.g;
        lightColor[2] = color.b;
    }
    nk_end(ctx);
}

输入处理代码

void process_input(void) {
    SDL_Event event;
    while (SDL_PollEvent(&event)) {
        nk_sdl_handle_event(&event);
        
        switch (event.type) {
            case SDL_QUIT:
                is_running = false;
                break;
            case SDL_KEYDOWN:
                keyStates[event.key.keysym.scancode] = true;
                break;
            case SDL_KEYUP:
                keyStates[event.key.keysym.scancode] = false;
                break;
            case SDL_MOUSEBUTTONDOWN:
                if(event.button.button == SDL_BUTTON_RIGHT)mouse_button_down = true;
                break;
            case SDL_MOUSEBUTTONUP:
                if(event.button.button == SDL_BUTTON_RIGHT)mouse_button_down = false;
                break;
            case SDL_MOUSEMOTION:
                    if(mouse_button_down){
                        process_mouse_move((float)event.motion.xrel,(float)event.motion.yrel,1);
                    }
                break;
            case SDL_MOUSEWHEEL:
                fov -= (float) event.wheel.y;
                if (fov < 1.0f)
                    fov = 1.0f;
                if (fov > 45.0f)
                    fov = 45.0f;
        }
    }
}

解决方案

1. 过滤窗口状态事件,阻断循环触发

问题根源是窗口最小化/恢复的SDL_WINDOWEVENT被Nuklear反复处理,形成状态切换循环。修改输入处理逻辑,单独处理这类事件并跳过后续重复处理:

// 全局添加窗口状态标志
_Bool is_window_minimized = false;

void process_input(void) {
    SDL_Event event;
    while (SDL_PollEvent(&event)) {
        // 优先处理窗口状态事件,避免循环触发
        if (event.type == SDL_WINDOWEVENT) {
            switch (event.window.event) {
                case SDL_WINDOWEVENT_MINIMIZED:
                case SDL_WINDOWEVENT_RESTORED:
                    nk_sdl_handle_event(&event);
                    is_window_minimized = (event.window.event == SDL_WINDOWEVENT_MINIMIZED);
                    continue; // 跳过后续处理,防止重复响应
            }
        }

        nk_sdl_handle_event(&event);
        
        switch (event.type) {
            case SDL_QUIT:
                is_running = false;
                break;
            case SDL_KEYDOWN:
                keyStates[event.key.keysym.scancode] = true;
                break;
            case SDL_KEYUP:
                keyStates[event.key.keysym.scancode] = false;
                break;
            case SDL_MOUSEBUTTONDOWN:
                if(event.button.button == SDL_BUTTON_RIGHT)mouse_button_down = true;
                break;
            case SDL_MOUSEBUTTONUP:
                if(event.button.button == SDL_BUTTON_RIGHT)mouse_button_down = false;
                break;
            case SDL_MOUSEMOTION:
                    if(mouse_button_down){
                        process_mouse_move((float)event.motion.xrel,(float)event.motion.yrel,1);
                    }
                break;
            case SDL_MOUSEWHEEL:
                fov -= (float) event.wheel.y;
                if (fov < 1.0f)
                    fov = 1.0f;
                if (fov > 45.0f)
                    fov = 45.0f;
        }
    }
}

2. 最小化时跳过UI渲染

窗口最小化后,暂停UI渲染可以避免Nuklear在不稳定状态下更新:

void renderUI(){
    if (is_window_minimized) return;

    static struct nk_colorf color = {1.0f, 0.0f, 0.0f, 1.0f};
    
    if (nk_begin(ctx, "Debug Window", nk_rect(0, 0, 410, 500), NK_WINDOW_BORDER | NK_WINDOW_MOVABLE | NK_WINDOW_MINIMIZABLE)) {
        // 原有渲染逻辑...
    }
    nk_end(ctx);
}

3. 检查Nuklear SDL绑定版本

如果使用的是旧版nk_sdl.c,可能存在窗口事件处理的bug,建议替换为最新官方绑定代码,确保事件逻辑没有重复触发窗口状态切换的问题。


内容的提问来源于stack exchange,提问作者Jambo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 15:05:56