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

SDL2主纹理在锁屏、切回应用或窗口Resize后丢失内容的问题

解决SDL2渲染目标纹理窗口状态变化后丢失内容的问题

哈哈,这个问题我用SDL2开发的时候踩过一模一样的坑!不管是Python的PySDL2还是C++版本,都会碰到这个情况——核心原因是当窗口经历锁屏解锁、切换应用、调整大小这些操作时,SDL会重建渲染上下文(renderer),绑定在它上面的渲染目标纹理(比如你的screen_texture)内容会被自动清空。你看到的“旧矩形丢失、新矩形保留”,是因为旧的已经存在纹理里被清掉了,而新的是事件触发后重新加入队列绘制到新纹理里的。

要解决这个问题,核心思路就是不要把绘制结果只存在纹理里,而是保存所有需要绘制的原始数据,在纹理被清空时重新绘制一遍。下面结合你的代码给出具体修改步骤:

第一步:保存所有矩形的原始数据

你现在只用block_queue存待绘制的新矩形,画完就丢了,这不行。得新增一个列表,把所有已经绘制过的矩形的位置和颜色都存起来,比如:

# 新增全局列表,保存所有已绘制的矩形(SDL_Rect + RGB颜色)
all_blocks = []

def request_data():
    # 假设你在这里生成新的矩形数据,比如:
    new_rect = sdl2.SDL_Rect(x, y, w, h)
    r, g, b = 255, 0, 0  # 示例颜色
    # 同时加入待绘制队列和全局保存列表
    block_queue.append((new_rect, r, g, b))
    all_blocks.append((new_rect, r, g, b))
    # 继续你的定时器逻辑...

第二步:监听窗口事件,重置纹理并重绘所有内容

在主循环里,你需要处理SDL的窗口事件,当检测到窗口需要重置的事件时,销毁旧纹理、创建新纹理,然后把all_blocks里的所有矩形重新画上去:

while running:
    event = sdl2.SDL_Event()
    while sdl2.SDL_PollEvent(event):
        if event.type == sdl2.SDL_QUIT:
            running = False
        # 处理窗口状态变化的事件
        elif event.type == sdl2.SDL_WINDOWEVENT:
            # 这些事件都会触发渲染上下文重建,导致纹理清空
            if event.window.event in [
                sdl2.SDL_WINDOWEVENT_RESIZED,  # 窗口大小调整
                sdl2.SDL_WINDOWEVENT_RESTORED, # 窗口从最小化恢复
                sdl2.SDL_WINDOWEVENT_EXPOSED   # 窗口被遮挡后重新显示
            ]:
                # 销毁旧纹理,避免内存泄漏
                sdl2.SDL_DestroyTexture(screen_texture)
                # 获取新的窗口尺寸
                window_w, window_h = sdl2.SDL_GetWindowSize(window)
                screen_texture_rect = sdl2.SDL_Rect(0, 0, window_w, window_h)
                # 重新创建渲染目标纹理,格式和访问模式要和原来一致
                screen_texture = sdl2.SDL_CreateTexture(
                    renderer,
                    sdl2.SDL_PIXELFORMAT_RGBA8888,
                    sdl2.SDL_TEXTUREACCESS_TARGET,
                    window_w,
                    window_h
                )
                # 重新绘制所有保存的矩形到新纹理
                sdl2.SDL_SetRenderTarget(renderer, screen_texture)
                for rect, r, g, b in all_blocks:
                    sdl2.SDL_SetRenderDrawColor(renderer, r, g, b, 255)
                    sdl2.SDL_RenderFillRect(renderer, rect)
                sdl2.SDL_SetRenderTarget(renderer, None)
    
    # 你原来的待绘制队列处理逻辑
    sdl2.SDL_SetRenderTarget(renderer, screen_texture)
    while len(block_queue) > 0:
        rect, r, g, b = block_queue[0]
        sdl2.SDL_SetRenderDrawColor(renderer, r, g, b, 255)
        sdl2.SDL_RenderFillRect(renderer, rect)
        del block_queue[0]
    sdl2.SDL_SetRenderTarget(renderer, None)
    
    # 你原来的屏幕渲染逻辑
    sdl2.SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255)
    sdl2.SDL_RenderClear(renderer)
    sdl2.SDL_RenderCopy(renderer, screen_texture, None, screen_texture_rect)
    sdl2.SDL_RenderPresent(renderer)

额外要注意的点

  • 确保all_blocks里的矩形数据是完整的,每次新增矩形都要正确添加,不要遗漏;
  • 重新创建纹理时,一定要用SDL_TEXTUREACCESS_TARGET访问模式,否则无法作为渲染目标使用;
  • 销毁旧纹理时必须调用SDL_DestroyTexture,不然会造成内存泄漏;
  • 除了上面列的三个窗口事件,你还可以根据实际情况添加其他可能触发渲染上下文重置的事件,比如SDL_WINDOWEVENT_MAXIMIZED。

这样修改后,不管窗口经历什么状态变化,你都能通过保存的原始数据重新生成完整的纹理内容,就不会再出现旧矩形丢失的问题了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 07:30:25