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
相关产品推荐
相关产品推荐

