如何在Linux下用SDL 1.2实现带按钮的弹窗(无需GUI工具包)
在SDL 1.2(Linux)中无额外依赖实现确认/取消弹窗
方案1:纯SDL 1.2自定义绘制弹窗
完全基于SDL 1.2自身API实现,无任何外部GUI工具包依赖,适合需要完全自定义弹窗样式的场景。
实现思路
- 创建独立SDL窗口(或在现有窗口上叠加SDL_Surface作为弹窗层)
- 手动绘制弹窗背景、边框、提示文本、确认/取消按钮
- 监听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工具,通过系统调用执行,无需自行绘制界面,代码简洁且弹窗风格与系统一致。
实现思路
- 通过
system()或popen()调用zenity命令行工具 - 根据命令退出码判断用户选择:
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
相关产品推荐
相关产品推荐

