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

请求协助:使用Nuklear GUI库开发带自定义标题栏的C++窗口

使用Nuklear在C++中实现自定义窗口

实现说明

Nuklear是纯GUI控件库,无窗口管理与渲染后端,因此我们结合SDL2完成窗口创建、事件处理和渲染,同时用SDL2_image加载图片,依托SDL提供文件对话框支持(需确保SDL版本≥2.24,低版本可替换为第三方文件对话框库)。

以下是满足需求的完整代码:黑色背景、自定义标题栏、中央图片+上下排列的文件打开按钮

#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#include "nuklear.h"
#include "nuklear_sdl2.h"
#include <cstdio>

// 窗口参数定义
#define WINDOW_WIDTH 800
#define WINDOW_HEIGHT 600
#define MAX_VERTEX_BUFFER 512 * 1024
#define MAX_ELEMENT_BUFFER 128 * 1024

// 全局资源变量
SDL_Window* window = nullptr;
SDL_Renderer* renderer = nullptr;
struct nk_context* ctx = nullptr;
SDL_Texture* image_texture = nullptr;
nk_image nk_img;

// 加载图片并转换为Nuklear可用格式
bool load_image(const char* path) {
    SDL_Surface* surface = IMG_Load(path);
    if (!surface) {
        printf("图片加载失败: %s\n", IMG_GetError());
        return false;
    }
    image_texture = SDL_CreateTextureFromSurface(renderer, surface);
    SDL_FreeSurface(surface);
    if (!image_texture) {
        printf("纹理创建失败: %s\n", SDL_GetError());
        return false;
    }
    // 获取图片尺寸并绑定到Nuklear图片结构
    int w, h;
    SDL_QueryTexture(image_texture, nullptr, nullptr, &w, &h);
    nk_img = nk_image_id((nk_handle)image_texture);
    nk_img.w = w;
    nk_img.h = h;
    return true;
}

// 打开系统文件对话框
void open_file_dialog() {
    SDL_FileDialogFilter filters[] = {{"所有文件", "*"}, {nullptr}};
    char* file_path = SDL_ShowOpenFileDialog(window, filters, nullptr);
    if (file_path) {
        printf("选中文件: %s\n", file_path);
        SDL_free(file_path);
    }
}

int main(int argc, char* argv[]) {
    // 初始化SDL
    if (SDL_Init(SDL_INIT_VIDEO) != 0) {
        printf("SDL初始化失败: %s\n", SDL_GetError());
        return 1;
    }
    // 初始化SDL_image(支持PNG格式)
    if (!(IMG_Init(IMG_INIT_PNG) & IMG_INIT_PNG)) {
        printf("SDL_image初始化失败: %s\n", IMG_GetError());
        SDL_Quit();
        return 1;
    }

    // 创建窗口与渲染器
    window = SDL_CreateWindow("自定义Nuklear窗口",
                              SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
                              WINDOW_WIDTH, WINDOW_HEIGHT,
                              SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE);
    if (!window) {
        printf("窗口创建失败: %s\n", SDL_GetError());
        IMG_Quit();
        SDL_Quit();
        return 1;
    }
    renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
    if (!renderer) {
        printf("渲染器创建失败: %s\n", SDL_GetError());
        SDL_DestroyWindow(window);
        IMG_Quit();
        SDL_Quit();
        return 1;
    }

    // 初始化Nuklear上下文
    ctx = nk_sdl_init(window, renderer);
    nk_sdl_font_stash_begin(&ctx->font);
    // 此处可加载自定义字体,示例使用默认字体
    nk_sdl_font_stash_end();

    // 加载示例图片(替换为你的图片路径)
    load_image("example.png");

    bool running = true;
    SDL_Event event;

    while (running) {
        // 事件处理循环
        while (SDL_PollEvent(&event)) {
            nk_sdl_handle_event(&event);
            if (event.type == SDL_QUIT) {
                running = false;
            }
        }

        // 绘制黑色背景
        SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
        SDL_RenderClear(renderer);
        nk_sdl_new_frame();

        // 创建带自定义标题栏的主窗口
        if (nk_begin(ctx, "Custom Window",
                     nk_rect(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT),
                     NK_WINDOW_BORDER | NK_WINDOW_MOVABLE | NK_WINDOW_SCALABLE | NK_WINDOW_TITLE)) {
            // 自定义标题栏区域
            nk_layout_row_dynamic(ctx, 30, 1);
            if (nk_button_label(ctx, "X")) { // 自定义关闭按钮
                running = false;
            }
            nk_layout_row_end(ctx);

            // 中央内容区域
            nk_layout_row_dynamic(ctx, WINDOW_HEIGHT - 60, 1);
            nk_group_begin(ctx, "Content", NK_WINDOW_NO_SCROLLBAR);
            {
                // 显示图片
                nk_layout_row_dynamic(ctx, nk_img.h, 1);
                nk_image(ctx, nk_img);

                // 上下排列的两个按钮
                nk_layout_row_dynamic(ctx, 40, 1);
                if (nk_button_label(ctx, "打开文件 1")) {
                    open_file_dialog();
                }
                if (nk_button_label(ctx, "打开文件 2")) {
                    open_file_dialog();
                }
            }
            nk_group_end(ctx);
        }
        nk_end(ctx);

        // 渲染Nuklear UI
        nk_sdl_render(NK_ANTI_ALIASING_ON, MAX_VERTEX_BUFFER, MAX_ELEMENT_BUFFER);
        SDL_RenderPresent(renderer);
    }

    // 资源清理
    SDL_DestroyTexture(image_texture);
    nk_sdl_shutdown();
    SDL_DestroyRenderer(renderer);
    SDL_DestroyWindow(window);
    IMG_Quit();
    SDL_Quit();
    return 0;
}

关键实现细节

  • 自定义标题栏:通过nk_begin启用NK_WINDOW_MOVABLE实现窗口拖动,手动添加关闭按钮;标题栏高度设为30px,内容区域占用剩余窗口空间。
  • 黑色背景:借助SDL渲染器的SDL_SetRenderDrawColor设置纯黑,再执行SDL_RenderClear完成背景绘制。
  • 图片显示:用SDL2_image加载图片并转换为SDL纹理,绑定到Nuklear的nk_image结构后,通过nk_image控件渲染。
  • 文件打开功能:调用SDL原生的SDL_ShowOpenFileDialog打开系统文件对话框,低版本SDL可替换为tinyfiledialogs等第三方库。

编译说明

以GCC为例,编译时需链接SDL2、SDL2_image和Nuklear库:

g++ main.cpp -o nuklear_app `sdl2-config --cflags --libs` -lSDL2_image -I./Nuklear/src

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 05:34:54