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

如何在Linux下用SDL 1.2实现带按钮的弹窗(无需GUI工具包)

在SDL 1.2(Linux)中无额外依赖实现确认/取消弹窗

方案1:纯SDL 1.2自定义绘制弹窗

完全基于SDL 1.2自身API实现,无任何外部GUI工具包依赖,适合需要完全自定义弹窗样式的场景。

实现思路

  1. 创建独立SDL窗口(或在现有窗口上叠加SDL_Surface作为弹窗层)
  2. 手动绘制弹窗背景、边框、提示文本、确认/取消按钮
  3. 监听SDL鼠标事件,判断点击区域是否落在按钮范围内,返回用户选择

简化代码示例

(假设已初始化SDL和SDL_ttf,SDL_ttf属于SDL生态组件,不算额外GUI工具包;若不想用SDL_ttf,可改用SDL自带的SDL_DrawString函数绘制简单文本)

#include <SDL/SDL.h>
#include <SDL/SDL_ttf.h>

typedef enum {
    POPUP_CANCEL,
    POPUP_CONFIRM,
    POPUP_CLOSE
} PopupResult;

PopupResult show_confirm_popup(SDL_Surface* screen, const char* message) {
    // 弹窗尺寸
    const int popup_w = 300;
    const int popup_h = 150;
    // 计算弹窗居中位置
    int popup_x = (screen->w - popup_w) / 2;
    int popup_y = (screen->h - popup_h) / 2;

    // 创建弹窗表面
    SDL_Surface* popup = SDL_CreateRGBSurface(SDL_SWSURFACE, popup_w, popup_h, 32, 0,0,0,0);
    SDL_FillRect(popup, NULL, SDL_MapRGB(popup->format, 240,240,240)); // 浅灰背景
    // 绘制边框
    SDL_Rect border = {0,0,popup_w,popup_h};
    SDL_FillRect(popup, &border, SDL_MapRGB(popup->format, 0,0,0));
    border.x += 2; border.y +=2; border.w -=4; border.h -=4;
    SDL_FillRect(popup, &border, SDL_MapRGB(popup->format, 240,240,240));

    // 加载字体绘制文本
    TTF_Font* font = TTF_OpenFont("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", 14);
    SDL_Color text_color = {0,0,0};
    SDL_Surface* text_surf = TTF_RenderUTF8_Solid(font, message, text_color);
    SDL_Rect text_pos = {(popup_w - text_surf->w)/2, 30, 0,0};
    SDL_BlitSurface(text_surf, NULL, popup, &text_pos);

    // 绘制确认/取消按钮
    SDL_Rect confirm_btn = {popup_w - 120, popup_h - 40, 100, 30};
    SDL_Rect cancel_btn = {20, popup_h -40, 100,30};
    SDL_FillRect(popup, &confirm_btn, SDL_MapRGB(popup->format, 0,128,255));
    SDL_FillRect(popup, &cancel_btn, SDL_MapRGB(popup->format, 200,200,200));
    // 按钮文本
    SDL_Surface* confirm_text = TTF_RenderUTF8_Solid(font, "确认", (SDL_Color){255,255,255});
    SDL_Surface* cancel_text = TTF_RenderUTF8_Solid(font, "取消", (SDL_Color){0,0,0});
    SDL_Rect confirm_text_pos = {confirm_btn.x + (confirm_btn.w - confirm_text->w)/2, confirm_btn.y + (confirm_btn.h - confirm_text->h)/2, 0,0};
    SDL_Rect cancel_text_pos = {cancel_btn.x + (cancel_btn.w - cancel_text->w)/2, cancel_btn.y + (cancel_btn.h - cancel_text->h)/2, 0,0};
    SDL_BlitSurface(confirm_text, NULL, popup, &confirm_text_pos);
    SDL_BlitSurface(cancel_text, NULL, popup, &cancel_text_pos);

    // 将弹窗绘制到主屏幕
    SDL_Rect popup_pos = {popup_x, popup_y, 0,0};
    SDL_BlitSurface(popup, NULL, screen, &popup_pos);
    SDL_Flip(screen);

    // 事件循环处理点击
    PopupResult result = POPUP_CLOSE;
    SDL_Event event;
    while(SDL_WaitEvent(&event)) {
        if(event.type == SDL_QUIT) {
            result = POPUP_CLOSE;
            break;
        }
        if(event.type == SDL_MOUSEBUTTONDOWN) {
            int mouse_x = event.button.x;
            int mouse_y = event.button.y;
            // 转换为弹窗局部坐标
            int local_x = mouse_x - popup_x;
            int local_y = mouse_y - popup_y;
            // 判断是否点击确认按钮
            if(local_x >= confirm_btn.x && local_x <= confirm_btn.x + confirm_btn.w &&
               local_y >= confirm_btn.y && local_y <= confirm_btn.y + confirm_btn.h) {
                result = POPUP_CONFIRM;
                break;
            }
            // 判断是否点击取消按钮
            if(local_x >= cancel_btn.x && local_x <= cancel_btn.x + cancel_btn.w &&
               local_y >= cancel_btn.y && local_y <= cancel_btn.y + cancel_btn.h) {
                result = POPUP_CANCEL;
                break;
            }
            // 点击弹窗外部关闭(可选)
            if(local_x <0 || local_x >= popup_w || local_y <0 || local_y >= popup_h) {
                result = POPUP_CLOSE;
                break;
            }
        }
    }

    // 清理资源
    SDL_FreeSurface(popup);
    SDL_FreeSurface(text_surf);
    SDL_FreeSurface(confirm_text);
    SDL_FreeSurface(cancel_text);
    TTF_CloseFont(font);
    return result;
}

// 使用示例(需先初始化SDL和TTF)
// int main() {
//     SDL_Init(SDL_INIT_VIDEO);
//     TTF_Init();
//     SDL_Surface* screen = SDL_SetVideoMode(800,600,32,SDL_SWSURFACE);
//     PopupResult res = show_confirm_popup(screen, "确定要执行此操作吗?");
//     if(res == POPUP_CONFIRM) {
//         // 执行确认逻辑
//     }
//     TTF_Quit();
//     SDL_Quit();
//     return 0;
// }

注意事项

  • 如果不需要自定义字体,可替换为SDL的SDL_DrawString函数(需包含SDL/SDL_gfxPrimitives.h,属于SDL_gfx组件)
  • 弹窗事件循环会阻塞主程序,若需要非阻塞可结合SDL事件队列异步处理

方案2:调用Linux原生桌面工具

利用Linux桌面环境自带的zenity或kdialog工具,通过系统调用执行,无需自行绘制界面,代码简洁且弹窗风格与系统一致。

实现思路

  1. 通过system()或popen()调用zenity命令行工具
  2. 根据命令退出码判断用户选择:
    • zenity --question --text="提示内容":退出码0为确认,1为取消,2为关闭窗口

代码示例

#include <stdlib.h>
#include <sys/wait.h>

typedef enum {
    POPUP_CANCEL,
    POPUP_CONFIRM,
    POPUP_CLOSE
} PopupResult;

PopupResult show_system_confirm_popup(const char* message) {
    char cmd[256];
    snprintf(cmd, sizeof(cmd), "zenity --question --text=\"%s\"", message);
    int exit_code = system(cmd);
    if(WIFEXITED(exit_code)) {
        int status = WEXITSTATUS(exit_code);
        switch(status) {
            case 0: return POPUP_CONFIRM;
            case 1: return POPUP_CANCEL;
            default: return POPUP_CLOSE;
        }
    }
    return POPUP_CLOSE;
}

// 使用示例
// int main() {
//     PopupResult res = show_system_confirm_popup("确定要执行此操作吗?");
//     if(res == POPUP_CONFIRM) {
//         // 执行确认逻辑
//     }
//     return 0;
// }

注意事项

  • zenity是GNOME桌面默认工具,KDE桌面可用kdialog --yesno "提示内容"替代,退出码逻辑一致
  • 若目标系统是极简无桌面环境的Linux,此方法不适用,需改用方案1

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 01:37:50