字符动态切换效果
#include <Windows.h>
#include <stdlib.h>
#include <vector>
#include <thread>
#include <mutex>
using namespace std;
struct SDisplay {
int Width;
int Height;
HDC OffScreenDC;
HBITMAP OffScreenBMP;
HBRUSH BlackBrush;
HBRUSH WhiteBrush;
HRGN CharRgn;
HFONT CharFont;
};
struct AnimationChar {
char Last;
char Current;
char Next;
uint8_t Step;
};
void AnimationCharProc(AnimationChar* AC) {
if (AC->Step) {
AC->Step++;
if (AC->Step == 216) {
AC->Step = 0;
AC->Last = AC->Current;
}
} else if (AC->Current != AC->Next) {
AC->Last = AC->Current;
AC->Current = AC->Next;
AC->Step = 1;
}
}
static struct {
SDisplay Display;
} _G;
AnimationChar AC[8];
static void _DoPaint() {
SDisplay& D = _G.Display;
HDC& hdc = D.OffScreenDC;
int w = D.Width;
int h = D.Height;
// uint8_t
SelectObject(hdc, D.WhiteBrush);
Rectangle(hdc, 0, 0, w, h);
SelectClipRgn(hdc, D.CharRgn);
SYSTEMTIME t;
GetSystemTime(&t);
char buffer[9];
snprintf(buffer, 9, "%02d:%02d:%02d", (t.wHour+8)%24, t.wMinute, t.wSecond);
uint16_t x[] = { 10, 50, 90, 120, 160, 200, 230, 270};
for (int i = 0; i < 8; i++) {
TCHAR last[2] = { AC[i].Last};
TCHAR current[2] = { AC[i].Current};
SelectObject(hdc, D.CharFont);
TextOut(hdc, x[i], 14 - AC[i].Step / 3, last, DT_CENTER);
TextOut(hdc, x[i], 86 - AC[i].Step / 3, current, DT_CENTER);
AC[i].Next = buffer[i];
AnimationCharProc(&AC[i]);
}
}
static void _OnPaint(HWND hWnd) {
PAINTSTRUCT ps;
BeginPaint(hWnd, &ps);
RECT rc;
GetClientRect(hWnd, &rc);
int w = rc.right - rc.left;
int h = rc.bottom - rc.top;
SDisplay& d = _G.Display;
HDC& hdc = d.OffScreenDC;
HBITMAP& hbmp = d.OffScreenBMP;
if (d.Width != w || d.Height != h) {
d.Width = w;
d.Height = h;
if (hdc == NULL) {
hdc = CreateCompatibleDC(ps.hdc);
}
HBITMAP newBmp = CreateCompatibleBitmap(hdc, w, h);
HBITMAP oldBmp = (HBITMAP)SelectObject(hdc, newBmp);
if (hbmp && hbmp == oldBmp) {
DeleteObject(hbmp);
}
hbmp = newBmp;
}
_DoPaint();
BitBlt(ps.hdc, 0, 0, w, h, hdc, 0, 0, SRCCOPY);
EndPaint(hWnd, &ps);
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
switch (uMsg) {
case WM_PAINT:
_OnPaint(hWnd);
//printf("WM_PAINT\n");
InvalidateRect(hWnd, NULL, false);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
return 0;
}
static const wchar_t* _GetWindowClassName() {
return L"SpectrumWindow";
}
static void _InitWindowClass() {
WNDCLASS wc = { 0 };
wc.lpfnWndProc = WndProc;
wc.hInstance = GetModuleHandle(NULL);
wc.lpszClassName = _GetWindowClassName();
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.style = CS_HREDRAW | CS_VREDRAW;
RegisterClass(&wc);
}
static void _CreateFont() {
LOGFONT lf = { 0 };
lf.lfHeight = 72;
lf.lfWeight = 900;
lf.lfCharSet = DEFAULT_CHARSET;
lstrcpy(lf.lfFaceName, TEXT("楷体"));
_G.Display.CharFont = CreateFontIndirect(&lf);
}
int main() {
_InitWindowClass();
_G.Display.BlackBrush = CreateSolidBrush(RGB(0, 0, 0));
_G.Display.WhiteBrush = CreateSolidBrush(RGB(255, 255, 255));
_G.Display.CharRgn = CreateRectRgn(10, 14, 410, 86);
_CreateFont();
HWND hWnd = CreateWindow(_GetWindowClassName(), L"动态数字", WS_OVERLAPPEDWINDOW,
0, 0, 1024, 600, NULL, NULL, GetModuleHandle(NULL), NULL);
ShowWindow(hWnd, SW_SHOW);
UpdateWindow(hWnd);
MSG msg = { 0 };
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}