为什么我的 window 只在我使用 SDL_PollEvent() 后显示?

Why does my window only get shown after I use SDL_PollEvent()?

我在 C 语言中使用 SDL2,并希望在不需要接受输入的情况下在屏幕上显示一些内容。但是当我 运行 显示黑屏的代码时 window 将无法打开。我继续做我知道会让它弹出的事情,并添加了一个 SDL_Event 变量并使用了 SDL_PollEvent()。我想知道为什么我必须这样做,以及是否有一种方法可以让我使用 SDL_Window 而无需轮询任何事件。

(例如:动画之类的东西)

问题代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <SDL2/SDL.h>

int main()
{
    if (SDL_Init(SDL_INIT_VIDEO))
    {
        fprintf(stderr, "Error while Initalizing SDL2: %s\n", SDL_GetError());
        return EXIT_FAILURE;
    }
    SDL_Window *window = SDL_CreateWindow("Connect Four", 100, 100, 500, 500, SDL_WINDOW_SHOWN);
    if (!window)
    {
        fprintf(stderr, "Error while Initalizing window: %s\n", SDL_GetError());
        return EXIT_FAILURE;
    }
    SDL_Renderer *renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
    if (!renderer)
    {
        SDL_DestroyWindow(window);
        fprintf(stderr, "Error while Initalizing renderer: %s\n", SDL_GetError());
        return EXIT_FAILURE;
    }
    SDL_Event events; //without these two lines
    SDL_PollEvent(&events); //the window will not open on screen
    SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
    SDL_RenderClear(renderer);    
    SDL_RenderPresent(renderer);
    SDL_Delay(3000);

    SDL_DestroyWindow(window);
    SDL_Quit();
    return EXIT_SUCCESS;
}

这可能会造成混淆,因为一些 SDL 示例(包括 SDL doc wiki)使用没有事件处理的“绘制和延迟”代码,但这不是在屏幕上显示内容的可靠方式。这些示例过于简化,并且是很久以前写的,当时它有点用,但仅用于最简单的事情,因为 3 秒可能不足以让 window 管理器杀死无响应的程序,或者让用户注意到 window 如果图像被最小化或被其他图像覆盖,图像会折叠 windows。

对您问题的简短回答是否定的,您的程序必须与 window 经理沟通(旁注 - 可能 没有必要一些 operating/graphics 系统);您必须获取事件并对特殊 window 事件做出反应(例如,您的 window 变得可见或用户请求调整大小)。在 SDL 中,这是通过 SDL_PumpEvents 调用完成的,它在内部执行此通信并生成您可以稍后检查的事件队列,因此您需要经常调用它,直接或间接通过 SDL_PollEventSDL_WaitEvent。如果你不这样做,window 经理可能不会对你好 - 根据 window 经理,你可能会看到“应用程序没有响应,让我们终止它”对话框,灰色显示 window或者,就像您的情况一样,根本没有 window (这种特殊情况是因为您在收到“您的 window 现在可见”事件之前已经呈现了渲染结果,因此您的图像被丢弃;这就是为什么在渲染之前处理事件会改变事情的发展方式。

但即便如此,一次处理事件也是不正确的。你所拥有的仍然是乐观的“让我们希望 3 秒内不会发生任何破坏”。如果你做动画,处理每一帧的事件;但是如果你有静态显示代码——把它当作动画来对待可能是个好主意。基本上你需要渲染循环,在开始时进行事件处理,并在必要时将代码重绘到 re-generate 你的图像。这种“必须”可能是无条件的(每次迭代都完全重绘),或者,如果您真的不想这样做(例如,出于处理成本的原因——大多数 GUI 程序在空闲时不会完全重绘),您仍然必须当 window 经理说您以前的图像不再有效时重绘 - SDL 通过 SDL_WINDOWEVENT_EXPOSED 类型的 SDL_WindowEvent 通知您。在这种情况下,您可能希望使用阻塞 SDL_WaitEvent 来避免不必要的迭代。