简体   繁体   中英

SDL (C)- Window Won't Appear without Event Loop

I'm trying to make a program that renders several colored rectangles within a window, then disappears after a few seconds. Basically, the following should appear (and I'll shortly explain how I got it to in the first place despite the problems I'm having):

The result (I'm new here by the way, is it possible to directly show images in a post instead of having to just include a link to it?)

The code I'm trying to run is as follows, obviously withstanding the inclusion of < stdio.h > and < SDL2/SDL.h > as well as definitions for "WINDOW_WIDTH" and "WINDOW_HEIGHT" which both appear in the code below (and are set to 800 and 640, respectively).

SDL_Window *window;
SDL_Renderer *renderer;

SDL_Init(SDL_INIT_VIDEO);

window = SDL_CreateWindow("Game Window", 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, 0);

if (window == NULL) {
        // In the case that the window could not be made...
        printf("Could not create window: %s\n", SDL_GetError());
        return 1;
    }

renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);

SDL_RenderClear(renderer);


SDL_SetRenderDrawColor(renderer, 140, 0, 100, 100);

SDL_Rect rect = { 0, 0, 800, 640 };

SDL_RenderFillRect(renderer, &rect);

SDL_SetRenderDrawColor(renderer, 60, 0, 255, 100);

SDL_Rect rect2 = { 40, 40, 720, 560 };

SDL_RenderFillRect(renderer, &rect2);

SDL_SetRenderDrawColor(renderer, 50, 140, 0, 100);

SDL_Rect rect3 = { 80, 80, 640, 480 };

SDL_RenderFillRect(renderer, &rect3);

SDL_SetRenderDrawColor(renderer, 200, 50, 25, 0);

SDL_Rect rect4 = { 120, 120, 560, 400 };

SDL_RenderFillRect(renderer, &rect4);

SDL_RenderPresent(renderer);

SDL_Delay(2000);

SDL_DestroyWindow(window);

SDL_DestroyRenderer(renderer);

SDL_Quit();
return 0;

This code seems like it should work fine, and it in fact does for the person in the aforementioned video (who, like me, is running this using Xcode on MacOS, albeit a far older version of it). However, the same thing that happens in the video does not seem to happen for me when I run my written code. Instead, the window simply doesn't appear at all. The code itself does indeed run, and perfectly fine for that matter without any errors or warnings, but the window with the multicolored rectangles doesn't show up at all before the delay is over and the SDL window is destroyed.

I realize that this question has been asked before on this website, and each with very similar issues, and I need to make it clear that yes, I've tried using an event loop instead and it works perfectly fine. For instance, if I run the following code- which is identical to the first batch of code except with "SDL_DELAY" replaced by an event handler which detects when the keyboard or mouse is pressed (and also includes < stdbool.h > for the boolean variable used)- the window appears just fine:

SDL_Window *window;
SDL_Renderer *renderer;

SDL_Init(SDL_INIT_VIDEO);

window = SDL_CreateWindow("Game Window", 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, 0);

if (window == NULL) {
        // In the case that the window could not be made...
        printf("Could not create window: %s\n", SDL_GetError());
        return 1;
    }

renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);

SDL_RenderClear(renderer);


SDL_SetRenderDrawColor(renderer, 140, 0, 100, 100);

SDL_Rect rect = { 0, 0, 800, 640 };

SDL_RenderFillRect(renderer, &rect);

SDL_SetRenderDrawColor(renderer, 60, 0, 255, 100);

SDL_Rect rect2 = { 40, 40, 720, 560 };

SDL_RenderFillRect(renderer, &rect2);

SDL_SetRenderDrawColor(renderer, 50, 140, 0, 100);

SDL_Rect rect3 = { 80, 80, 640, 480 };

SDL_RenderFillRect(renderer, &rect3);

SDL_SetRenderDrawColor(renderer, 200, 50, 25, 0);

SDL_Rect rect4 = { 120, 120, 560, 400 };

SDL_RenderFillRect(renderer, &rect4);

SDL_RenderPresent(renderer);

SDL_Event e;
bool quit = false;
while (!quit){
    while (SDL_PollEvent(&e)){
        if (e.type == SDL_QUIT){
            quit = true;
        }
        if (e.type == SDL_KEYDOWN){
            quit = true;
        }
        if (e.type == SDL_MOUSEBUTTONDOWN){
            quit = true;
        }
    }
}

SDL_DestroyWindow(window);

SDL_DestroyRenderer(renderer);

SDL_Quit();
return 0;

However , this is different from what the first attempt was trying to achieve, which as I said is a window that is rendered and then gets destroyed after a brief period of time. How am I supposed to get this to happen if I can't use the first set of code shown above? Moreover, why does such a set-up using SDL_DELAY clearly work for the person in the video (which for the sake of convenience, can again be found here ) but not when I try to input it?

You're right it was asked many times before. Short answer is "window managers behave differently, and worse, they may have compositing enabled". Basically you create window, start drawing, tell window manager you're done, and some time later get signal that your window you thought you're drawing into was created just now, so would you kindly redraw whatever you wanted to display. The same thing happens when your window is resized, restored from minimised state, overshadowed by other windows, etc - that was always a thing, simple 3-line examples just ignored it; window manager is not responsible for keeping your image, whenever something happens it just sends you signal to redraw (doesn't mean it isn't allowed to keep image for its own purposes, mostly for compositing, previews, etc.). Before compositing age it "worked most of the times".

Window manager also may rely on target application's event processing to show "application not responding" dialog.

So actually your second version is still incorrect as you draw only once and don't watch for redraw events. Games often don't bother with these events as their image is very dynamic anyway and redraw unconditionally. You not only need event loop but also redraw.

As for how you can break loop when some time is passed - you need to look at the time and when given interval have passed trigger your quit or break loop in other way. Aside from OS provided time functions there are SDL_GetTicks , SDL_AddTimer , etc..

Here is an example:

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

#define WINDOW_WIDTH 800
#define WINDOW_HEIGHT 600

int main(int argc, char **argv) {
    SDL_Window *window;
    SDL_Renderer *renderer;

    SDL_Init(SDL_INIT_VIDEO);

    window = SDL_CreateWindow("Game Window", 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, 0);
    if (window == NULL) { return 1; }

    renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
    if (renderer == NULL) { return 1; }

    const Uint32 time_started = SDL_GetTicks();
    SDL_Event e;
    bool quit = false;
    while (!quit){
        // check for timeout
        if(SDL_GetTicks() - time_started > 2000) { quit = true; }

        while (SDL_PollEvent(&e)){
            if (e.type == SDL_QUIT){
                quit = true;
            }
            if (e.type == SDL_KEYDOWN){
                quit = true;
            }
            if (e.type == SDL_MOUSEBUTTONDOWN){
                quit = true;
            }
        }

        // break early - doesn't really matter
        if(quit) { break; }

        SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
        SDL_RenderClear(renderer);
        SDL_SetRenderDrawColor(renderer, 140, 0, 100, 100);
        SDL_Rect rect = { 0, 0, 800, 640 };
        SDL_RenderFillRect(renderer, &rect);
        SDL_SetRenderDrawColor(renderer, 60, 0, 255, 100);
        SDL_Rect rect2 = { 40, 40, 720, 560 };
        SDL_RenderFillRect(renderer, &rect2);
        SDL_SetRenderDrawColor(renderer, 50, 140, 0, 100);
        SDL_Rect rect3 = { 80, 80, 640, 480 };
        SDL_RenderFillRect(renderer, &rect3);
        SDL_SetRenderDrawColor(renderer, 200, 50, 25, 0);
        SDL_Rect rect4 = { 120, 120, 560, 400 };
        SDL_RenderFillRect(renderer, &rect4);
        SDL_RenderPresent(renderer);
    }

    SDL_DestroyRenderer(renderer);
    SDL_DestroyWindow(window);
    SDL_Quit();
    return 0;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM