图像不会绘制到屏幕 C++
Posted
技术标签:
【中文标题】图像不会绘制到屏幕 C++【英文标题】:Image wont draw to screen C++ 【发布时间】:2010-02-22 21:23:09 【问题描述】:我正在学习教程。我正在尝试将 .bmp 文件绘制到屏幕上。它构建没有错误,但没有出现图像。根据这本书,我应该看到图像在随机位置弹出。下面是我的代码。作者不推荐这种技术来绘制对象,他只是为了演示。万一你想知道。
图片是一个 25x25 的红色正方形。
#include <windows.h>
#include <iostream>
#include <time.h>
using namespace std;
const string APPTITLE = "Game Loop";
HWND window;
HDC device;
bool gameover = false;
void DrawBitmap(char *filename, int x, int y)
//load the bitmap image
HBITMAP image = (HBITMAP)LoadImage(0,"c.bmp", IMAGE_BITMAP,0,0, LR_LOADFROMFILE);
BITMAP bm;
GetObject(image, sizeof(BITMAP), &bm);
HDC hdcImage = CreateCompatibleDC(device);
SelectObject(hdcImage,image);
BitBlt(
device,
x,y,
bm.bmWidth, bm.bmHeight,
hdcImage,
0,0,
SRCCOPY);
//deletec the device context and bitmap
DeleteDC(hdcImage);
DeleteObject((HBITMAP)image);
bool Game_Init()
srand(time(NULL));
return 1;
void Game_Run()
if(gameover == true) return;
RECT rect;
GetClientRect(window, &rect);
//draw bitmap at random location
int x = rand() % (rect.right - rect.left);
int y = rand() % (rect.bottom - rect.top);
DrawBitmap("c.bmp",x,y);
void Game_End()
//free the device
ReleaseDC(window,device);
LRESULT CALLBACK WinProc(HWND hWnd, UINT message, WPARAM WParam, LPARAM lparam)
switch(message)
case WM_DESTROY:
gameover = true;
PostQuitMessage(0);
break;
return DefWindowProc(hWnd, message, WParam, lparam);
ATOM MyRegisterClass(HINSTANCE hInstance)
//set the new windows properties
WNDCLASSEX wc;
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = (WNDPROC) WinProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = NULL;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
wc.lpszMenuName = NULL;
wc.lpszClassName= APPTITLE.c_str();
wc.hIconSm = NULL;
return RegisterClassEx(&wc);
bool InitInstance(HINSTANCE hInstance, int nCmdShow)
//create a new window
window = CreateWindow(
APPTITLE.c_str(),
APPTITLE.c_str(),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
640,480,
NULL,
NULL,
hInstance,
NULL);
//was there an error creating the window ?
if(window == 0) return 0;
//display the window
ShowWindow(window, nCmdShow);
UpdateWindow(window);
device = GetDC(window);
return 1;
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
//declare variables
MSG msg;
//register the class
MyRegisterClass(hInstance);
//initialize application
if(!InitInstance(hInstance, nCmdShow)) return 0;
//initilize the game
if(!Game_Init()) return 0;
//main message loop
while(!gameover)
if(PeekMessage(&msg,NULL, 0, 0,PM_REMOVE))
TranslateMessage(&msg);
DispatchMessage(&msg);
Game_Run();
Game_End();
return msg.wParam;
我不确定是不是因为我把图片放在了错误的位置。但如果是这样的话。我认为它会引发错误。我将图像放在源文件夹的根目录下。
[编辑]
另外,当我重建时,我收到一个警告,这可能是一个原因,但这里是警告
1>------ Rebuild All started: Project: Begin, Configuration: Debug Win32 ------
1>Deleting intermediate and output files for project 'Begin', configuration 'Debug|Win32'
1>Compiling...
1>main.cpp
1>c:\users\numerical25\documents\visual studio 2008\projects\begin\begin\main.cpp(39) : warning C4244: 'argument' : conversion from 'time_t' to 'unsigned int', possible loss of data
1>Compiling manifest to resources...
1>Microsoft (R) Windows (R) Resource Compiler Version 6.1.6723.1
1>Copyright (C) Microsoft Corporation. All rights reserved.
1>Linking...
1>LINK : C:\Users\numerical25\Documents\Visual Studio 2008\Projects\Begin\Debug\Begin.exe not found or not built by the last incremental link; performing full link
1>Embedding manifest...
1>Microsoft (R) Windows (R) Resource Compiler Version 6.1.6723.1
1>Copyright (C) Microsoft Corporation. All rights reserved.
1>Build log was saved at "file://c:\Users\numerical25\Documents\Visual Studio 2008\Projects\Begin\Begin\Debug\BuildLog.htm"
1>Begin - 0 error(s), 1 warning(s)
========== Rebuild All: 1 succeeded, 0 failed, 0 skipped ==========
【问题讨论】:
您需要检查 Win32 函数调用的结果。其中任何一个都可能失败,没有人会知道。 只是好奇,你如何在 C++ 中跟踪?也许这可能会帮助我弄清楚功能是否失败。因为如果它这样做了,函数不会停止吗?? 不,如果一个函数失败,它不会停止,它只是返回一个错误指示,你可以得到一个错误代码。查看每个 Windows 调用的文档以获取详细信息。 Visual Studio 将单步执行程序,如果您想检查单个点,则在一行上停止。 【参考方案1】:代码确实有效,您只是忘记将c.bmp
放在正确的位置。如果您从资源管理器启动程序,则将其放入项目输出文件夹(即 bin/Debug);如果您从 Visual Studio 启动程序,则将其放入项目文件夹。
【讨论】:
成功了。我不确定图像相对于应用程序的运行位置。但相对于 .exe 文件运行是有道理的。谢谢 我数不清那天我写了多少简单的小游戏,我会花几个小时挠头,直到我意识到这一点……每一次。【参考方案2】:对于“工作”的足够宽松的定义,您的代码似乎有效。除非你已经修改了代码(相当多的)以使其工作,否则我的建议是找到一个不同的教程来遵循——至少对我来说,现在的大部分内容都很不起眼。
例如,Game_Run()
将位图文件的名称作为参数传递给Draw_Bitmap()
,但该参数被忽略,Draw_Bitmap()
使用硬编码的文件名。
PeekMessage()
循环使程序看起来像是在大约 25 年前编写的,当时是 16 位 Windows 时代(即使在那时也可以说不是那么好)。在新代码中使用PeekMessage()
很少(如果有的话)有充分的理由,而且确实使用它的代码可能早就应该进行大修了。主循环通常使用GetMessage()
,您可以(例如)使用SetTimer
(持续时间为0)计算绘制位图的新坐标,然后调用InvalidateRect()
进行绘制。曾经有一个公平的论点认为,其中涉及的额外消息会导致过多的开销,但在现代机器上,它会在使用大约 10% 或更少的 CPU 时跟上显示器刷新率。
但是,为了降低 CPU 使用率,您需要稍微重构代码 - 现在,每次绘制时,您都会获得窗口矩形,从磁盘重新加载 BMP,将 BMP 选择到兼容的 DC ,最后BitBlt
ing 将图像显示在屏幕上。这就是优化将产生影响的代码部分——根据强烈的偏好,您希望它只需调用BitBlt
并完成。其余代码应移至其他地方,以便仅在需要时发生。例如,您可以检索响应WM_SIZE
的窗口矩形,并将其保存在中间。由于您在持续时间内使用相同的位图,请加载一次,然后从它们中显示它。
【讨论】:
是的,我注意到 Draw_Bitmap() 中的忽略参数。以及。我纠正了它。我正在努力为这本书找一个勘误表。本书为《游戏编程入门》第三版。阿瑟还表示,这种格式将是他在书中最后一次使用的格式,他承认这不是绘制对象的正确方法。他正在演示如果您不使用直接 x sdk,您将如何渲染对象。这是本书的开头,只是为了让事情顺利进行。我打算再给它一个机会。 @numerical25:即使不使用 DirectX,这也不是真正(至少在 IMO)绘制任何东西的“正确”方式。以上是关于图像不会绘制到屏幕 C++的主要内容,如果未能解决你的问题,请参考以下文章