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

SDL 2.0使用Blit绘制BMP图像仅第二次启动窗口可正常显示问题

问题原因分析

你的问题核心是没有处理SDL窗口的重绘事件,具体可拆解为3个问题点:

  • 返回值误用:SDL_UpdateWindowSurface 函数成功执行时返回0,失败返回负数,你直接将返回值赋值给控制循环退出的quit变量,属于潜在逻辑错误,不过这不是你遇到显示异常的核心原因。
  • 未处理重绘事件(核心问题):通过SDL_GetWindowSurface获取的窗口表面内存是由窗口系统管理的,遇到以下任意场景时表面内容都会自动失效,需要手动重新绘制:
    • 窗口被其他应用遮挡后重新露出
    • 窗口被拖动、调整大小
    • 窗口首次创建完成后系统触发的强制重绘请求
      你的代码仅在初始化阶段执行了1次图像blit和窗口更新操作,事件循环中没有处理SDL_WINDOWEVENT_EXPOSED类型的重绘事件,首次运行时初始化绘制的内容会被系统后续的重绘请求清空,因此窗口显示空白。
  • 多窗口偶现显示的原因:短时间内多次运行程序创建同规格窗口时,窗口系统可能复用了未完全释放的旧窗口表面缓存,刚好保留了之前绘制的图像内容,这属于未定义行为,不是稳定生效的逻辑。拖动窗口花屏也正是因为拖动触发了重绘请求,你没有重新绘制导致表面内容丢失。
修复方案

你需要在事件循环中添加重绘事件的处理逻辑,每次窗口需要重绘时重新把BMP图像blit到窗口表面并更新窗口,修复后的代码如下:

#include <iostream>
#include <SDL.h>

int main(int argc, char ** argv)
{
    bool quit = false;
    SDL_Event event;

    if (SDL_Init(SDL_INIT_VIDEO) < 0) {
        return 1;
    }

    SDL_Window * gWindow = SDL_CreateWindow("SDL_Yo",
    SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 640,480,SDL_WINDOW_SHOWN );
    if (gWindow == NULL) {
        SDL_Quit();
        return 1;
    }

    SDL_Surface* gScreenSurface = SDL_GetWindowSurface( gWindow );
    if( gScreenSurface == NULL )
    {
        SDL_DestroyWindow(gWindow);
        SDL_Quit();
        return 1;
    }
    SDL_Surface* gHelloWorld = SDL_LoadBMP("IMG_0004.bmp");
    if( gHelloWorld == NULL )
    {
        SDL_DestroyWindow(gWindow);
        SDL_Quit();
        return 1;
    }

    // 初始绘制一次
    SDL_BlitSurface( gHelloWorld, NULL, gScreenSurface, NULL );
    SDL_UpdateWindowSurface( gWindow );

    while (!quit)
    {
        SDL_WaitEvent(&event);

        switch (event.type)
        {
            case SDL_QUIT:
                quit = true;
                break;
            // 新增重绘事件处理
            case SDL_WINDOWEVENT:
                if (event.window.event == SDL_WINDOWEVENT_EXPOSED) {
                    SDL_BlitSurface( gHelloWorld, NULL, gScreenSurface, NULL );
                    SDL_UpdateWindowSurface( gWindow );
                }
                break;
        }
    }

    // 主动释放资源
    SDL_FreeSurface(gHelloWorld);
    SDL_DestroyWindow(gWindow);
    SDL_Quit();

    return 0;
}
额外说明

如果需要避免拖动窗口时的画面撕裂问题,也可以改用SDL渲染器(SDL_CreateRenderer)API进行绘制,渲染器会自动管理纹理的重绘逻辑,不需要手动处理暴露事件。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 13:36:04