我无法阻止闪烁。我得到了添加dubbel-buffering的建议。我该怎么做?
#include <iostream>
#include <windows.h>
#include <string>
#include <fstream>
#include <vector>
using namespace std;
namespace {
const int ID_NEW = 1;
const int ID_QUIT = 2;
const int ID_ABOUT = 3;
const int NORTH_BUTTON_ID = 4;
const int SOUTH_BUTTON_ID = 5;
const int WEST_BUTTON_ID = 6;
const int EAST_BUTTON_ID = 7;
const int ID_FINISHED_GAME = 8;
int x = 0;
int y = 0;
int xStart = 0;
int yStart = 0;
int windowHeight = 400;
int windowWidth = 500;
char level1[20][21];
int noOfMoves = 0;
}
void readLevel(string fileName, char level[20][21]) {
char character{};
ifstream file(fileName);
int i = 0;
int j = 0;
if (file.is_open()) {
while (file >> character) {
level[j][i] = character;
if (level[j][i] == 's') {
y = yStart = j;
x = xStart = i;
}
if (++i % 20 == 0) {
i = 0;
j++;
}
}
file.close();
}
}
void restart(){
x = xStart;
y = yStart;
noOfMoves = 0;
}
LRESULT CALLBACK WinProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
HDC hdc{ 0 };
PAINTSTRUCT ps{ 0 };
switch (msg) {
case WM_CLOSE:
PostQuitMessage(0);
return 0;
case WM_COMMAND:
switch (LOWORD(wParam)){
case ID_ABOUT:
MessageBox(hwnd, L"About this program!", L"About", MB_OK);
return 0;
case ID_NEW:
restart();
return 0;
case ID_QUIT:
if (MessageBox(0, L"Do you really want to quit?", L"Are you sure?", MB_YESNO) == IDYES) {
PostQuitMessage(0);
return 0;
}
case NORTH_BUTTON_ID:
if (level1[y - 1][x] != '1') {
y -= 1;
noOfMoves++;
}
break;
case SOUTH_BUTTON_ID:
if (level1[y + 1][x] != '1'){
y += 1;
noOfMoves++;
}
break;
case WEST_BUTTON_ID:
if (level1[y][x - 1] != '1'){
x -= 1;
noOfMoves++;
}
break;
case EAST_BUTTON_ID:
if (level1[y][x + 1] != '1') {
x += 1;
noOfMoves++;
}
break;
}
if (level1[y][x] == 'e') {
wstring moves = L"Congratulations, you finished the game with " + to_wstring(noOfMoves);
MessageBox(hwnd, moves.c_str(), L"Finished game", MB_OK);
}
case WM_PAINT: {
char wall[2] = { "W" };
char floor[2] = { 'W' };
char current[2] = { "X" };
char goal[2] = { "G" };
wstring position = L"Position = [" + to_wstring(x) + L", " + to_wstring(y) + L"]";
wstring moves = L"Move = " + to_wstring(noOfMoves);
hdc = BeginPaint(hwnd, &ps);
TextOut(hdc, 20, 200, position.c_str(), position.size());
TextOut(hdc, 20, 220, moves.c_str(), moves.size());
for (int i = 0; i < 20; i++) {
for (int j = 0; j < 20; j++) {
if (level1[j][i] == '1') {
SetTextColor(hdc, RGB(0, 0, 0));
SetBkColor(hdc, RGB(0, 0, 0));
TextOut(hdc, 14 * i + 190, 14 * j + 20, LPCTSTR(wall), strlen(wall));
}
SetBkColor(hdc, RGB(255, 255, 255));
if (level1[j][i] == '0') {
SetTextColor(hdc, RGB(255, 255, 255));
TextOut(hdc, 14 * i + 190, 14 * j + 20, LPCTSTR(floor), strlen(floor));
}
SetTextColor(hdc, RGB(0, 0, 0));
if (i == x && j == y)
TextOut(hdc, 14 * i + 190, 14 * j + 20, LPCTSTR(current), strlen(current));
if (level1[j][i] == 'e')
TextOut(hdc, 14 * i + 190, 14 * j + 20, LPCTSTR(goal), strlen(goal));
}
}
EndPaint(hwnd, &ps);
break;
}
case WM_ERASEBKGND:
return true;
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
HMENU CreateMainMenu() {
HMENU main = CreateMenu();
HMENU file = CreateMenu();
AppendMenu(file, MF_STRING, ID_NEW, L"&New");
AppendMenu(file, MF_SEPARATOR, 0, 0);
AppendMenu(file, MF_STRING, ID_QUIT, L"&Quit");
AppendMenu(main, MF_POPUP, (UINT_PTR)file, L"&File");
HMENU help = CreateMenu();
AppendMenu(help, MF_STRING, ID_ABOUT, L"&About");
AppendMenu(main, MF_POPUP, (UINT_PTR)help, L"&Help");
return main;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow) {
readLevel("level1.txt", level1);
WNDCLASS wc = { 0 };
wc.hbrBackground = NULL;
wc.lpfnWndProc = WinProc;
wc.hInstance = hInstance;
wc.lpszClassName = L"MyWindowClass";
RegisterClass(&wc);
HWND hwnd = CreateWindow(L"MyWindowClass", L"The Maze",
WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,
windowWidth, windowHeight, 0, CreateMainMenu(), hInstance, 0);
HWND buttonNorth = CreateWindow(L"BUTTON", L"NORTH", WS_CHILD | WS_VISIBLE,
10, 20, 150, 40, hwnd, (HMENU)NORTH_BUTTON_ID, hInstance, 0);
HWND buttonSouth = CreateWindow(L"BUTTON", L"SOUTH", WS_CHILD | WS_VISIBLE,
10, 60, 150, 40, hwnd, (HMENU)SOUTH_BUTTON_ID, hInstance, 0);
HWND buttonEast = CreateWindow(L"BUTTON", L"EAST", WS_CHILD | WS_VISIBLE,
10, 140, 150, 40, hwnd, (HMENU)EAST_BUTTON_ID, hInstance, 0);
HWND buttonWest = CreateWindow(L"BUTTON", L"WEST", WS_CHILD | WS_VISIBLE,
10, 100, 150, 40, hwnd, (HMENU)WEST_BUTTON_ID, hInstance, 0);
UpdateWindow(hwnd);
ShowWindow(hwnd, nCmdShow);
MSG msg = { 0 };
BOOL isRunning = true;
while (isRunning) {
while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) {
if (msg.message == WM_QUIT)
isRunning = false;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
wc.hbrBackground = NULL;
InvalidateRect(hwnd, NULL, FALSE);
Sleep(10);
}
return 0;
}
答案 0 :(得分:2)
当成员 Retired Ninja 表示,您使用原始设备(hdc
创建兼容设备上下文),并创建与原始设备上下文兼容的位图(位图大小为等于你画出你的东西的矩形的大小)。
然后将这个新创建的位图选择到刚刚创建的兼容设备上下文中,并在其上绘制所有内容。
然后您只需将BitBlt(...)
兼容设备上下文转换为原始设备上下文。
不要忘记进行适当的清理以避免GDI泄漏。
您的代码应如下所示:
case WM_PAINT:
{
// skipped the initialization part to preserve space
// just copy those, they are irrelevant for your problem
hdc = BeginPaint(hwnd, &ps);
// create memory DC and memory bitmap where we shall do our drawing
HDC memDC = CreateCompatibleDC( hdc );
// get window's client rectangle. We need this for bitmap creation.
RECT rcClientRectangle;
GetClientRect( hwnd, &rcClientRect );
// now we can create bitmap where we shall do our drawing
HBITMAP bmp = CreateCompatibleBitmap( hdc,
rcClientRect.right - rcClientRect.left,
rcClientRect.bottom - rcClientRect.top );
// we need to save original bitmap, and select it back when we are done,
// in order to avoid GDI leaks!
HBITMAP oldBmp = (HBITMAP)SelectObject( memDC, bmp );
// now you draw your stuff in memory dc;
// just substitute hdc with memDC in your drawing code,
// like I did below:
TextOut( memDC, //...
TextOut( memDC, //...
for (int i = 0; i < 20; i++)
{
for (int j = 0; j < 20; j++)
{
if (level1[j][i] == '1')
{
SetTextColor( memDC, //...
SetBkColor( memDC, //...
TextOut( memDC, //...
}
SetBkColor( memDC, //...
if (level1[j][i] == '0')
{
SetTextColor( memDC, //...
TextOut( memDC, //...
}
SetTextColor( memDC, //...
if (i == x && j == y)
TextOut( memDC, //...
if (level1[j][i] == 'e')
TextOut( memDC, //...
}
}
// OK, everything is drawn into memory DC,
// now is the time to draw that final result into our target DC
BitBlt( hdc, 0, 0, rcClientRect.right - rcClientRect.left,
rcClientRect.bottom - rcClientRect.top, memDC, 0, 0, SRCCOPY );
// all done, now we need to cleanup
SelectObject( memDC, oldBmp ); // select back original bitmap
DeleteObject( bmp ); // delete bitmap since it is no longer required
DeleteDC( memDC ); // delete memory DC since it is no longer required
EndPaint(hwnd, &ps);
break;
}