Linux中SDL2空白透明窗口

3

这是一段我尝试在我的Linux计算机上运行的SDL2示例代码,我的操作系统是Ubuntu 18.04,并且使用了KDE Plasma桌面环境(我安装了多个桌面环境以备不时之需)。

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

int main(int argc, char** argv)
{
    if(SDL_Init(SDL_INIT_VIDEO) != 0){
        std::cerr << "SDL_Init() Error: " << SDL_GetError() << std::endl;
        return 1;
    }

    SDL_Window* win = SDL_CreateWindow(
        "Hello world",
        SDL_WINDOWPOS_CENTERED,
        SDL_WINDOWPOS_CENTERED,
        640,480,
        0
    );

    if(win == nullptr){
        std::cerr << "SDL_CreateWindow() Error: " << SDL_GetError() << std::endl;
        return 1;  
    }

    //Create and init the renderer
    SDL_Renderer* ren = SDL_CreateRenderer(win, -1, 0);
    if(ren == nullptr){
        std::cerr << "SDL_CreateRenderer() Error: " << SDL_GetError() << std::endl;
        SDL_DestroyWindow(win);
        return 1;
    }

    //Render something
    SDL_RenderSetLogicalSize(ren,640,480);

    //Set colour of renderer
    SDL_SetRenderDrawColor(ren,255,0,0,255);

    //Clear the screen to the set colour
    SDL_RenderClear(ren);

    //Show all the has been done behind the scenes
    SDL_RenderPresent(ren);

    //Delay so that we can see what is on the screen
    SDL_Delay(5000);

    //Clean Up
    SDL_DestroyRenderer(ren);
    SDL_DestroyWindow(win);
    SDL_Quit();

    return 0;
}

当我第一次运行程序时,应该出现的红窗口只出现了一次。所有后续执行都会产生一个透明的空窗口,并将背景中的任何内容拖动到窗口中。我在SDL_CreateWindow()中尝试使用SDL_WINDOW_SHOWN标志以及SDL_CreateRenderer()中的SDL_RENDER_ACCELERATED标志。唯一再次出现红屏幕的方法是重新启动系统。即使我使用IDE(CodeLite)编译并运行此代码,仍然得到相同的结果。这个SO上的问题与此类似,但OP不使用Linux,问题也不完全相同。这个网站上的其他帖子提到事件处理,但我还没有深入了解。如果必要的话,我会感激一些关于它的资源,因为文档没有解释得很清楚。 更新:该程序在另一台运行Lubuntu 18.10的计算机上可以正常运行。
1个回答

1

将阻塞所有事件处理(如通知X11/Wayland和窗口管理器您的进程仍在运行)的SDL_Delay()替换为循环调用SDL_PumpEvents(),可以直接(如下所示)或间接地通过SDL_PollEvent()/SDL_WaitEvent()调用:

const Uint32 startMs = SDL_GetTicks();
while( SDL_GetTicks() - startMs < 5000 )
{
    SDL_PumpEvents();

    //Render something
    SDL_RenderSetLogicalSize(ren,640,480);

    //Set colour of renderer
    SDL_SetRenderDrawColor(ren,255,0,0,255);

    //Clear the screen to the set colour
    SDL_RenderClear(ren);

    //Show all the has been done behind the scenes
    SDL_RenderPresent(ren);
}

全部在一起:

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

int main( int argc, char** argv )
{
    if( SDL_Init( SDL_INIT_VIDEO ) != 0 )
    {
        std::cerr << "SDL_Init() Error: " << SDL_GetError() << std::endl;
        return 1;
    }

    SDL_Window* win = SDL_CreateWindow
        (
        "Hello world",
        SDL_WINDOWPOS_CENTERED,
        SDL_WINDOWPOS_CENTERED,
        640, 480,
        0
        );

    if( win == nullptr )
    {
        std::cerr << "SDL_CreateWindow() Error: " << SDL_GetError() << std::endl;
        return 1;
    }

    //Create and init the renderer
    SDL_Renderer* ren = SDL_CreateRenderer( win, -1, 0 );
    if( ren == nullptr )
    {
        std::cerr << "SDL_CreateRenderer() Error: " << SDL_GetError() << std::endl;
        SDL_DestroyWindow( win );
        return 1;
    }

    const Uint32 startMs = SDL_GetTicks();
    while( SDL_GetTicks() - startMs < 5000 )
    {
        SDL_PumpEvents();

        //Render something
        SDL_RenderSetLogicalSize( ren, 640, 480 );

        //Set colour of renderer
        SDL_SetRenderDrawColor( ren, 255, 0, 0, 255 );

        //Clear the screen to the set colour
        SDL_RenderClear( ren );

        //Show all the has been done behind the scenes
        SDL_RenderPresent( ren );
    }

    //Clean Up
    SDL_DestroyRenderer( ren );
    SDL_DestroyWindow( win );
    SDL_Quit();

    return 0;
}

天啊,它成功了!你能给我指一些资源,让我可以读更多关于这个的内容吗? - DS2830
1
@DS2830:一般的概念是一个事件循环:操作系统/窗口系统将事件(输入、定时器、“嘿,我需要你重新绘制屏幕的一部分”)传递给您的应用程序,您的应用程序需要及时地对每个事件做出“好的,知道了”的回应(即不要在sleep()中阻塞5秒钟:)),否则系统会认为您的程序已经死亡或变得无响应。 - genpfault
此外,在这种情况下,我们使用了一种临时的方法,而不是库本来打算供我们使用的东西(显然是因为它是必需的)。在现实世界的软件中这样做是否合理?为什么或为什么不? - DS2830
1
@DS2830:你正在使用的“将东西扔到屏幕上,睡眠5秒钟,然后退出”的序列,我只在SDL测试程序中看到过;“真正的”应用程序将使用适当的SDL_PollEvent()/SDL_WaitEvent()事件循环来响应用户输入和重新绘制。 - genpfault

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接