#c #winapi
Вопрос:
Ниже у меня есть фрагмент кода, показывающий, что я пробовал.
#include lt;stdio.hgt; #include lt;stdlib.hgt; #include lt;windows.hgt; #include lt;windowsx.hgt; #define WC_MAIN "MainClass" #define WC_NUMBER "NumberClass" LRESULT CALLBACK NumberProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); LRESULT CALLBACK MainWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); void InitClasses(void) { WNDCLASS wc; memset(amp;wc, 0, sizeof(wc)); wc.hbrBackground = GetStockObject(WHITE_BRUSH); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.lpfnWndProc = MainWndProc; wc.lpszClassName = WC_MAIN; RegisterClass(amp;wc); wc.lpfnWndProc = NumberProc; wc.lpszClassName = WC_NUMBER; RegisterClass(amp;wc); } #define NUMBER_SPEED 2 #define NUMBER_TICK_SPEED 25 #define NUMBER_TICKS 55 typedef struct { UINT ticks; HBITMAP buffer; } NUMBERINFO; HWND CreateNumber(HWND parent, const char *text, int x, int y, COLORREF color) { NUMBERINFO *ni = malloc(sizeof(*ni)); HDC hdc = GetDC(NULL); HFONT oldFont = NULL; SIZE s; GetTextExtentPoint32(hdc, text, strlen(text), amp;s); SelectObject(hdc, oldFont); BITMAPINFO bmi; bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); bmi.bmiHeader.biWidth = s.cx; bmi.bmiHeader.biHeight = s.cy; bmi.bmiHeader.biPlanes = 1; bmi.bmiHeader.biBitCount = 32; // four 8-bit components bmi.bmiHeader.biCompression = BI_RGB; bmi.bmiHeader.biSizeImage = s.cx * s.cy * 4; COLORREF *pvBits; HBITMAP buffer = CreateDIBSection(hdc, amp;bmi, DIB_RGB_COLORS, (void**) amp;pvBits, NULL, 0); HDC bufferDc = CreateCompatibleDC(hdc); HBITMAP oldBmp = SelectObject(bufferDc, buffer); oldFont = NULL; SetTextAlign(bufferDc, TA_TOP | TA_LEFT); SetBkMode(bufferDc, TRANSPARENT); SetTextColor(bufferDc, color); TextOut(bufferDc, 0, 0, text, strlen(text)); SelectObject(bufferDc, oldFont); SelectObject(bufferDc, oldBmp); DeleteDC(bufferDc); ReleaseDC(NULL, hdc); ni-gt;buffer = buffer; return CreateWindow(WC_NUMBER, text, WS_VISIBLE | WS_CHILD, x - (s.cx gt;gt; 1), y - (s.cy gt;gt; 1), s.cx, s.cy, parent, NULL, NULL, ni); } LRESULT CALLBACK NumberProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { NUMBERINFO *info = (NUMBERINFO*) GetWindowLongPtr(hWnd, GWLP_USERDATA); switch(msg) { case WM_CREATE: info = ((CREATESTRUCT*) lParam)-gt;lpCreateParams; SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR) info); SetTimer(hWnd, 0, NUMBER_TICK_SPEED, NULL); info-gt;ticks = NUMBER_TICKS; return 0; case WM_DESTROY: return 0; case WM_TIMER: { RECT rc; GetWindowRect(hWnd, amp;rc); HWND parent = GetParent(hWnd); MapWindowPoints(HWND_DESKTOP, parent, (POINT*) amp;rc, 2); rc.top -= NUMBER_SPEED; if(!--info-gt;ticks) { DestroyWindow(hWnd); return 0; } SetWindowPos(hWnd, NULL, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top - NUMBER_SPEED, SWP_NOREDRAW | SWP_NOCOPYBITS); // redraw parent call erases last shown number RedrawWindow(GetParent(hWnd), amp;rc, NULL, RDW_ERASE | RDW_INVALIDATE | RDW_UPDATENOW); return 0; } case WM_ERASEBKGND: return 1; case WM_PAINT: { PAINTSTRUCT ps; HDC hdc = BeginPaint(hWnd, amp;ps); RECT r; GetClientRect(hWnd, amp;r); HDC bufferDc = CreateCompatibleDC(hdc); HBITMAP oldBmp = SelectObject(bufferDc, info-gt;buffer); BLENDFUNCTION bfn; bfn.BlendOp = AC_SRC_OVER; bfn.BlendFlags = 0; bfn.SourceConstantAlpha = info-gt;ticks * 0xFF / NUMBER_TICKS; bfn.AlphaFormat = 0; //TransparentBlt(hdc, 0, 0, r.right, r.bottom, bufferDc, 0, 0, r.right, r.bottom, 0); AlphaBlend(hdc, 0, 0, r.right, r.bottom, bufferDc, 0, 0, r.right, r.bottom, bfn); SelectObject(bufferDc, oldBmp); DeleteDC(bufferDc); EndPaint(hWnd, amp;ps); return 0; } } return DefWindowProc(hWnd, msg, wParam, lParam); } LRESULT CALLBACK MainWndProc (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch(msg) { case WM_DESTROY: PostQuitMessage(0); return 0; case WM_ERASEBKGND: return 1; case WM_PAINT: { InvalidateRect(hWnd, NULL, FALSE); PAINTSTRUCT ps; HDC hdc = BeginPaint(hWnd, amp;ps); // draw gradient (red to green) RECT r; GetClientRect(hWnd, amp;r); GRADIENT_RECT gr; gr.UpperLeft = 0; gr.LowerRight = 1; TRIVERTEX pVertex[2] = { { 0, 0, 0xFF00, 0x0000, 0x0000, 0xFF00 }, { r.right, r.bottom, 0x0000, 0xFF00, 0x0000, 0xFF00 } }; GradientFill(hdc, pVertex, 2, amp;gr, 2, GRADIENT_FILL_RECT_H); EndPaint(hWnd, amp;ps); return 0; } } return DefWindowProc(hWnd, msg, wParam, lParam); } int main() { InitClasses(); HWND mainWindow = CreateWindow(WC_MAIN, "Title", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, GetModuleHandle(NULL), NULL); ShowWindow(mainWindow, 1); UpdateWindow(mainWindow); MSG msg; while(GetMessage(amp;msg, NULL, 0, 0)) { TranslateMessage(amp;msg); DispatchMessage(amp;msg); // adding a number at mouse position if pressed (testing) if(msg.message == WM_LBUTTONDOWN) { RECT r; GetClientRect(mainWindow, amp;r); int x = GET_X_LPARAM(msg.lParam); int y = GET_Y_LPARAM(msg.lParam); CreateNumber(mainWindow, "123", x, y, 0xFFFF00); } } return 0; }
Это рисует текст любого цвета, и каждый раз, когда тикает таймер, текст становится более блеклым (более прозрачным), но черный фон растрового изображения, на котором был нарисован текст, рисуется, но я не хочу, чтобы фон присутствовал, только текст.
Я бы предположил, что мне нужна комбинация TransparentBlt
и AlphaBlend
.
Как бы я продолжал решать эту проблему?
Ответ №1:
Решение было довольно простым. Он должен был использоваться AC_SRC_ALPHA
для AlphaFormat
члена BLENDFUNCTION
и для того, чтобы это работало , установите альфа-значения HBITMAP
буфера.
После того, как буфер (тот, что внутри NUMBERINFO
) создан (в CreateNumber
; проверьте код вопроса для справки), необходимо перебрать все цвета и при необходимости установить альфа-значение 255.
for(int i = s.cx * s.cy; i--; pvBits ) { if(*pvBits) *pvBits |= 0xFF000000; // make non black pixels opaque }
И установив флаг в WM_PAINT
: bfn.AlphaFormat = AC_SRC_ALPHA;