A test in C++/Win32 (12* 12, change nXMax to 4...)
You, or someone else, can easily convert it to MFC =>
#include <windows.h>
#include <tchar.h>
#include <vector>
#include <uxtheme.h> // BeginBufferedPaint
#pragma comment (lib, "uxtheme")
#pragma comment(linker,"\"/manifestdependency:type='win32' \
name='Microsoft.Windows.Common-Controls' version='6.0.0.0' \
processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
HINSTANCE hInst;
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int nWidth = 402, nHeight = 426;
std::vector<RECT> rectangles;
std::vector<int> cells;
int nXMax = 12, nYMax = 12, nCellSize = 32;
HBRUSH hBrushWhite, hBrushGreen;
int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpCmdLine, _In_ int nCmdShow)
{
BufferedPaintInit();
hInst = hInstance;
WNDCLASSEX wcex =
{
sizeof(WNDCLASSEX), CS_HREDRAW | CS_VREDRAW, WndProc, 0, 0, hInst, LoadIcon(NULL, IDI_APPLICATION),
LoadCursor(NULL, IDC_ARROW), (HBRUSH)(COLOR_WINDOW + 1), NULL, TEXT("WindowClass"), NULL,
};
if (!RegisterClassEx(&wcex))
return MessageBox(NULL, TEXT("Cannot register class !"), TEXT("Error"), MB_ICONERROR | MB_OK);
int nX = (GetSystemMetrics(SM_CXSCREEN) - nWidth) / 2, nY = (GetSystemMetrics(SM_CYSCREEN) - nHeight) / 2;
HWND hWnd = CreateWindowEx(0, wcex.lpszClassName, TEXT("Test"), WS_OVERLAPPEDWINDOW, nX, nY, nWidth, nHeight, NULL, NULL, hInst, NULL);
if (!hWnd)
return MessageBox(NULL, TEXT("Cannot create window !"), TEXT("Error"), MB_ICONERROR | MB_OK);
ShowWindow(hWnd, SW_SHOWNORMAL);
UpdateWindow(hWnd);
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int)msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
switch (message)
{
case WM_CREATE:
{
int n = 0;
for (int x = 0; x < nXMax; x++)
{
for (int y = 0; y < nYMax; y++)
{
RECT r = { (x * nCellSize) + 1, (y * nCellSize) + 1, (x * nCellSize) + 1 + (nCellSize - 1), (y * nCellSize) + 1 + (nCellSize - 1) };
rectangles.push_back(r);
cells.push_back(0);
if ((x % 2 == 0 && y % 2 == 0) || (x % 2 != 0 && y % 2 != 0))
{
cells[n] = 1;
}
n++;
}
}
hBrushGreen = CreateSolidBrush(RGB(0, 255, 0));
hBrushWhite = CreateSolidBrush(RGB(255, 255, 255));
return 0;
}
break;
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hDC = BeginPaint(hWnd, &ps);
HDC hDCTarget = hDC;
HDC hBufferedDC = NULL;
RECT rect;
GetClientRect(hWnd, &rect);
HPAINTBUFFER hBufferedPaint = BeginBufferedPaint(hDCTarget, &rect, BPBF_TOPDOWNDIB, 0, &hBufferedDC);
if (hBufferedPaint == NULL)
hBufferedDC = hDCTarget;
if (rectangles.size() > 0)
{
int n = 0;
for (int x = 0; x < nXMax; x++)
{
for (int y = 0; y < nYMax; y++)
{
Rectangle(hBufferedDC, x * nCellSize, y * nCellSize, x * nCellSize + nCellSize + 1, y * nCellSize + nCellSize + 1);
FillRect(hBufferedDC, &(rectangles.at(n)), (cells[n] == 1) ? hBrushGreen : hBrushWhite);
n++;
}
}
}
EndBufferedPaint(hBufferedPaint, TRUE);
EndPaint(hWnd, &ps);
}
break;
case WM_LBUTTONDOWN:
{
int n = 0;
for (std::vector<RECT>::const_iterator citer = rectangles.begin(); citer != rectangles.end(); ++citer)
{
POINT pt = { LOWORD(lParam), HIWORD(lParam) };
if (PtInRect(&(*citer), pt))
{
cells[n] = (cells[n] == 0) ? 1 : 0;
Beep(8000, 10);
}
n++;
}
InvalidateRect(hWnd, NULL, FALSE);
}
break;
case WM_DESTROY:
{
PostQuitMessage(0);
BufferedPaintUnInit();
return 0;
}
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}