在C++中的SDL2窗口上显示.bmp时出现问题



第一个问题,我真的需要帮助。所以我试着在C++上学习SDL2api。我用的是树莓派3型号B。我第一次在Youtube上学习教程(更具体地说,CodingMadeEasy)但现在我正在学习lazyfo的教程。我复制了芝加哥商品交易所的代码,并尝试显示图像(.bmp),但窗口也没有显示任何内容SDL_GetError()没有报告任何错误。我想我写的代码一定有问题,或者我从网上下载的图像可能不是.bmp,所以我在这里查看了lazyfo的教程http://lazyfoo.net/tutorials/SDL/02_getting_an_image_on_the_screen/index.php并下载了源代码和.bmp文件。但当我运行它时,我得到了相同的输出:一个空白窗口和SDL_GetError()在控制台上不报告任何内容。这是代码:

/*This source code copyrighted by Lazy Foo' Productions 
(2004-2015)
and may not be redistributed without written permission.*/
//Using SDL and standard IO
#include <SDL2/SDL.h>
#include <stdio.h>
//Screen dimension constants
const int SCREEN_WIDTH = 640;
const int SCREEN_HEIGHT = 480;
//Starts up SDL and creates window
bool init();
//Loads media
bool loadMedia();
//Frees media and shuts down SDL
void close();
//The window we'll be rendering to
SDL_Window* gWindow = NULL;
//The surface contained by the window
SDL_Surface* gScreenSurface = NULL;
//The image we will load and show on the screen
SDL_Surface* gHelloWorld = NULL;
bool init()
{
//Initialization flag
bool success = true;
//Initialize SDL
if( SDL_Init( SDL_INIT_VIDEO ) < 0 )
{
printf( "SDL could not initialize! SDL_Error: %sn", SDL_GetError() );
success = false;
}
else
{
//Create window
gWindow = SDL_CreateWindow( "SDL Tutorial", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN );
if( gWindow == NULL )
{
printf( "Window could not be created! SDL_Error: %sn", SDL_GetError() );
success = false;
}
else
{
//Get window surface
gScreenSurface = SDL_GetWindowSurface( gWindow );
}
}
return success;
}
bool loadMedia()
{
//Loading success flag
bool success = true;
//Load splash image
gHelloWorld = SDL_LoadBMP( "02_getting_an_image_on_the_screen/hello_world.bmp" );
if( gHelloWorld == NULL )
{
printf( "Unable to load image %s! SDL Error: %sn", "02_getting_an_image_on_the_screen/hello_world.bmp", SDL_GetError() );
success = false;
}
return success;
}
void close()
{
//Deallocate surface
SDL_FreeSurface( gHelloWorld );
gHelloWorld = NULL;
//Destroy window
SDL_DestroyWindow( gWindow );
gWindow = NULL;
//Quit SDL subsystems
SDL_Quit();
}
int main( int argc, char* args[] )
{
//Start up SDL and create window
if( !init() )
{
printf( "Failed to initialize!n" );
}
else
{
//Load media
if( !loadMedia() )
{
printf( "Failed to load media!n" );
}
else
{
//Apply the image
SDL_BlitSurface( gHelloWorld, NULL, gScreenSurface, NULL );
//Update the surface
SDL_UpdateWindowSurface( gWindow );
//Wait two seconds
SDL_Delay( 2000 );
}
}
//Free resources and close SDL
close();
return 0;
}

如果您想要.bmp文件,请访问上面的链接并下载源代码和文件。它不允许我上传。这是我得到的输出:输出。这种透明的,灰色的窗户。我使用的是gnu c++编译器,并使用进行编译

g++ 02_getting_an_image_on_the_screen.cpp -w -lSDL2 -o hl

然后打开透明的灰色窗户。我想它是透明的,因为我的终端是这样配置的。为了了解问题所在,我删除了.bmp,看看sdl是否报告了错误,它确实报告了,这意味着它可以在.bmp位于正确位置时读取它,但无法显示它。我在谷歌上搜索了几个小时,一无所获。关于堆栈溢出,最接近我的问题是SDL窗口没有显示我甚至尝试了轮询事件,以便让系统有机会运行事件循环,正如那里所建议的那样,但无论窗口打开多长时间,.bmp都不会显示。更奇怪的是,这不是第一次发生在我身上。一年前我试着学习SDL2,但当时也发生了同样的事情。我使用的是一台2GB RAM的廉价Windows 10笔记本电脑,使用的是代码::块(mingw编译器版本),除了窗口不是透明的,它是白色的,就像你用sdl创建窗口时一样由于某种原因,代码块不允许我将窗口设置为nullptr,说它无法识别它是什么,所以我不得不将其设置为NULL。正因为如此,我认为没有显示.bmp的窗口也是编译器的错。所以我下载了Microsoft visual studio 2015但结果是一样的:没有显示任何图像。当时,我放弃了,但现在我回来了,因为我有了一台新机器(rpi model 3b)和一个新编译器(gnu c/c++),我认为SDL不会再困扰我了,但SDL似乎没有放弃。我真的需要帮助。是的,.bmp在正确的位置,我在代码中包含了它的正确名称。请记住,我已经在2台机器、3个编译器、2个非常不同的操作系统和2个不同的cpu架构(armv71和x86)上尝试过这样做,但现在它变得令人沮丧。我有一些惊人的想法,如果SDL2允许的话,这些想法可以很容易地实现。很抱歉发了这么长的帖子,我们非常感谢您的帮助。非常感谢。

您的代码在我的iMac上运行良好。我做的唯一更改如下,所以也许可以尝试做同样的更改,看看它是否适合你。

首先,有许多不同类型的BMP文件,可能您已经掌握了一个在图片查看器应用程序中运行良好的BMP文件。但SDL对加载它感到"不满意"。为了避免疑问,请使用ImageMagick创建您自己的BMP文件,然后您可以确定您有一个好的BMP文件了。我在终端中使用过这个:

convert -size 640x480 gradient:red-cyan image.bmp

其次,在任何"集成开发环境">之外运行程序,即仅从终端运行,所有图像都在当前目录中(没有路径),并且名称中没有空格。原因是IDE可能会破坏事件循环和屏幕更新,而且IDE通常看起来运行的是一个程序,但实际上运行的是/some/where/else/Debug/program,这会混淆打开文件的路径,例如"02_getting_an_image_on_the_screen/hello_world.bmp",这也意味着目录分隔符不会引起问题。

第三,考虑使用pkgconfig来获取头路径和库。例如,在我的Mac上,它添加了一个我可能不知道的线程安全定义:

pkg-config --cflags --libs sdl2

样本输出

-D_THREAD_SAFE -I/usr/local/include/SDL2 -L/usr/local/lib -lSDL2

所以,为了编译,我使用:

g++ main.cpp $(pkg-config --cflags --libs sdl2) -o main

如果我回答这个老问题违反了一些规则,请原谅,但它帮助我找到了解决我面临的类似问题的方法。我有几乎完全相同的代码,只是在SDL2的LazyFoo指南9/17/22版本之后的主函数中有一点不同。这是我编辑的代码,没有删除它的含义。

int main(int argc, char *argv[])
{
if (game_init() == 0) {
printf("Failed to initialize game!n");
exit(EXIT_FAILURE);
}
if (game_load_media() == 0) {
printf("Failed to load media!n");
exit(EXIT_FAILURE);
}
SDL_BlitSurface(gHelloSurface, NULL, gScreenSurface, NULL);
SDL_UpdateWindowSurface(gWindow);
SDL_Event e;
int quit = 0;
while( quit == 0 ) {
SDL_PollEvent( &e );
if( e.type == SDL_QUIT )
quit = true;
}
game_close();
return 0;
}

问题是,该窗口有时是透明的,有时它正确加载图像并显示bmp图像。通过对SDL_WindowFlags和函数调用安排的实验,我发现通过延迟:

SDL_BlitSurface(gHelloSurface, NULL, gScreenSurface, NULL);
SDL_Delay(100);
SDL_UpdateWindowSurface(gWindow);

或者简单地移动SDL_UpdateWindowSurface(gWindow);while循环内部解决了这个问题。作为一个初学者,我的猜测是有些东西没有及时初始化,但通过延迟调用或重复调用可以解决这个问题。

此外。我在Window 10和Kubuntu 22.04上都遇到了这个问题,在X11上使用了KDE Plasma 5.24.7、KDE Framework 5.92.0、Qt 5.15.3和内核5.15。同样的黑客修复了两个平台的问题。

最新更新