Function to automatically create DrawText in RECT - c++

I am writing the WinAPI Application, and I tried to write a function, that would automate for me creating Rectangles for text input (with Font, BkMode, TextColor), that then is called by DrawContent function called by WM_PAINT. The text does not appear, after I call ELW::AddTextControl.
LRESULT CALLBACK ELW::WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_PAINT:
{
ELW::DrawContent(hWnd, hInst, hdc);
}
break;
case WM_CLOSE:
{
DestroyWindow(hWnd);
UnregisterClass(CLASS_NAME, hInst);
}
break;
case WM_SYSCOMMAND:
{
if (wParam == SC_CLOSE);
break;
}
}
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
// Content drawing
void ELW::DrawContent(HWND hWnd, HINSTANCE hInst, HDC hdc)
{
PAINTSTRUCT ps;
hdc = BeginPaint(hWnd, &ps);
RECT testowyRectangle = { 0, 1 , 20 , 30 };
FillRect(hdc, &ps.rcPaint, (HBRUSH)(COLOR_GRAYTEXT + 1));
ELW::AddTextControl("Testowy test", 80, 80, 100, 100, CUSTOM_COLOR_YELLOW_COLORREF, 10, "Euroscope", hdc);
EndPaint(hWnd, &ps);
};
void ELW::AddTextControl(const char* text, int xPos, int yPos, int xSize, int ySize, COLORREF rgb, int fontSize, const char* fontName, HDC hdc)
{
RECT TextRectangle = { xPos, yPos, ( xPos + xSize ) , ( yPos + ySize ) }; // Left, Top, Right, Bottom
if (rgb == NULL)
rgb = RGB(0, 0, 0);
if (fontSize == NULL)
fontSize = 10;
if (fontName == NULL)
fontName = "Euroscope";
HFONT hFont = CreateFont(fontSize, 8, 0, 0, 600, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_OUTLINE_PRECIS, CLIP_DEFAULT_PRECIS, CLEARTYPE_QUALITY, VARIABLE_PITCH, TEXT(fontName));
SelectObject(hdc, hFont);
SetBkMode(hdc, TRANSPARENT);
SetTextColor(hdc, rgb);
DrawText(hdc, TEXT(text), strlen(text), &TextRectangle, DT_CENTER | DT_NOCLIP);
}

Found an error:
strlen(text)
should be
strlen(TEXT(text))

Related

GDI+ Text Flickering and Now with Black background

I'm working on a windows desktop application and I noticed to my dismay that my text was flickering so upon searching I found two methods - return true for erasebkgnd and double buffering. The first method didn't do anything and the second made my background all black for some reason and it still flickers.
Below is where I call paint and the buffering:
case WM_PAINT: {
PAINTSTRUCT ps;
HDC screen = BeginPaint(hWnd, &ps);
putImage(screen, hWnd);
RECT rc;
GetClientRect(hWnd, &rc);
HDC memdc;
auto hbuff = BeginBufferedPaint(screen, &rc, BPBF_COMPATIBLEBITMAP, NULL, &memdc);
EndBufferedPaint(hbuff, TRUE);
EndPaint(hWnd, &ps); } break;
and this next part is the putImage function
void putImage(HDC hdc, HWND hWnd)
{
Graphics graphic(hdc);
graphic.DrawImage(Image::FromFile(filePath), 10, 10);
RedrawWindow(hWnd, NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW);
}
I was wondering what the problem was and if there is a fix for this.
my background all black
This issue is due to not filling the your background. You can fill your background before draw the image like this:
RECT rc;
GetClientRect(hWnd, &rc);
FillRect(screen, &rc, GetSysColorBrush(COLOR_WINDOW));
flickering
This issue is due to not using BeginBufferedPaint in correct manner. Call BeginBufferedPaint before drawing the image like this:
case WM_PAINT: {
PAINTSTRUCT ps;
HDC screen = BeginPaint(hWnd, &ps);
HPAINTBUFFER hbuff = BeginBufferedPaint(ps.hdc, &ps.rcPaint, BPBF_COMPATIBLEBITMAP, NULL, &screen);
if (hbuff)
{
RECT rc;
GetClientRect(hWnd, &rc);
FillRect(screen, &rc, GetSysColorBrush(COLOR_WINDOW));
putImage(screen, hWnd);
hr = EndBufferedPaint(hbuff, TRUE);
}
EndPaint(hWnd, &ps); } break;
And don't forget to call BufferedPaintInit and BufferedPaintUnInit. For example like this:
case WM_CREATE:
{
hr = BufferedPaintInit();
}
break;
//...
case WM_DESTROY:
{
BufferedPaintUnInit();
PostQuitMessage(0);
}
break;
Update: The complete code.
void putImage(HDC hdc, HWND hWnd)
{
Graphics graphic(hdc);
Image* image = Image::FromFile(L"path-to\\test.png");
Status status = graphic.DrawImage(image, 10, 10);
RedrawWindow(hWnd, NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW);
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
DWORD err;
HRESULT hr;
static HDC memdc;
switch (message)
{
case WM_CREATE:
{
hr = BufferedPaintInit();
}
break;
case WM_COMMAND:
{
int wmId = LOWORD(wParam);
// Parse the menu selections:
switch (wmId)
{
case IDM_ABOUT:
DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
}
break;
case WM_PAINT: {
PAINTSTRUCT ps;
HDC screen = BeginPaint(hWnd, &ps);
HPAINTBUFFER hbuff = BeginBufferedPaint(ps.hdc, &ps.rcPaint, BPBF_COMPATIBLEBITMAP, NULL, &screen);
if (hbuff)
{
RECT rc;
GetClientRect(hWnd, &rc);
FillRect(screen, &rc, GetSysColorBrush(COLOR_WINDOW));
putImage(screen, hWnd);
hr = EndBufferedPaint(hbuff, TRUE);
}
EndPaint(hWnd, &ps); } break;
case WM_DESTROY:
{
BufferedPaintUnInit();
PostQuitMessage(0);
}
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}

CreateBitmap image is not printing on window

I need to load a bmp image from file and load image data into buffer and then create new image from it. (I have a reason for doing this way). I wrote a sample program to mimic my project scenario.
LRESULT CALLBACK WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
static BITMAP bm;
static HBITMAP bmpSource = NULL;
static HBITMAP hbmp=NULL;
static HDC hdcSource = NULL;
static HDC hdcDestination= NULL;
static PAINTSTRUCT ps;
BITMAPINFO bitmap_info[2] = {0};
if (Msg == WM_CREATE) {
bmpSource = (HBITMAP)LoadImage(NULL, L"bmp00004.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
GetObject(bmpSource, sizeof(BITMAP), &bm);
bitmap_info->bmiHeader.biSize = sizeof(bitmap_info->bmiHeader);
int ret = GetDIBits(hdcSource, bmpSource, 0, bm.bmHeight, NULL, bitmap_info,DIB_RGB_COLORS);
LPVOID *lpvBits = (LPVOID*) malloc(3*(bm.bmWidth * bm.bmHeight * sizeof(DWORD)));
int gotData = GetDIBits(hdcSource, bmpSource, 0,bm.bmHeight,lpvBits, bitmap_info, DIB_RGB_COLORS);
hbmp = (HBITMAP) CreateBitmap(bm.bmWidth, bm.bmHeight, bm.bmPlanes, bm.bmBitsPixel ,lpvBits);
hdcSource = CreateCompatibleDC(GetDC(0));
SelectObject(hdcSource, hbmp);
return 0;
}else if (Msg == WM_PAINT) {
hdcDestination = BeginPaint(hWnd, &ps);
BitBlt(hdcDestination, 0, 0,bm.bmWidth , bm.bmHeight, hdcSource, 0, 0, SRCCOPY);
EndPaint(hWnd, &ps);
return 0;
}else if (Msg == WM_DESTROY) {
DeleteDC(hdcSource);
EndPaint(hWnd, &ps);
DeleteObject(bmpSource);
DeleteObject(hbmp);
}
return DefWindowProc(hWnd, Msg, wParam, lParam);
}
I am expecting program to print the image on the window.
Now the newly created image is not displayed on window. All I can see is a gray box.
Your code can be considerably simplified. There is no need to call GetDIBits (which you are doing before you set up hdcSource anyway), and you should clean up properly and minimise the use of static variables. Something like the following (error checking omitted for clarity):
LRESULT CALLBACK WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
static HBITMAP bmpSource;
if (Msg == WM_CREATE) {
bmpSource = (HBITMAP)LoadImage(NULL, L"bmp00004.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
return 0;
}
if (Msg == WM_PAINT) {
PAINTSTRUCT ps;
HDC hdcDestination = BeginPaint(hWnd, &ps);
BITMAP bm;
GetObject(bmpSource, sizeof(bm), &bm);
HDC hdcSource = CreateCompatibleDC(hdcDestination);
HGDIOBJ hOldBmp = SelectObject(hdcSource, bmpSource);
BitBlt(hdcDestination, 0, 0,bm.bmWidth , bm.bmHeight, hdcSource, 0, 0, SRCCOPY);
SelectObject(hdcSource, hOldBmp);
DeleteDC(hdcSource);
EndPaint(hWnd, &ps);
return 0;
}
if (Msg == WM_DESTROY)
DeleteObject(bmpSource);
return DefWindowProc(hWnd, Msg, wParam, lParam);
}
It seems you are attempting to read a bitmap file and write to another HBITMAP handle, for whatever reason...
LoadImage returns a compatible bitmap (unless you specify LR_CREATEDIBSECTION), therefore you need CreateCompatibleBitmap followed by SetDIBits to duplicate that source bitmap.
For some reason you have declared BITMAPINFO bminfo[2] But you only need one bminfo object. You need new or malloc to allocate enough memory for one object. Note that you cannot randomly swap arrays for pointers and vice-versa. If you used a debugger you would notice the functions failed and bminfo was not properly filled.
It's easier if you setup BITMAPINFOHEADER yourself, rather than let GetDIBits fill that parameter:
LRESULT CALLBACK WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
static HDC hdc_memory;
static HBITMAP hbmp_src;
static HBITMAP hbmp_dst;
static BITMAP bm;
if(Msg == WM_CREATE)
{
hbmp_src = (HBITMAP)LoadImage(NULL, L"file.bmp",
IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
HDC hdc = GetDC(0);
hdc_memory = CreateCompatibleDC(hdc);
GetObject(hbmp_src, sizeof(bm), &bm);
int w = bm.bmWidth;
int h = bm.bmHeight;
if(h < 0) h = -h;
int size = ((w * bm.bmBitsPixel + 31) / 32) * 4 * h;
BITMAPINFOHEADER bi = { sizeof(bi), w, h, bm.bmPlanes, bm.bmBitsPixel };
BYTE* bits = new BYTE[size];
GetDIBits(hdc, hbmp_src, 0, h, bits, (BITMAPINFO*)&bi, DIB_RGB_COLORS);
//change the pixel data in bits if that's your goal ...
hbmp_dst = CreateCompatibleBitmap(hdc, w, h);
SetDIBits(hdc, hbmp_dst, 0, h, bits, (BITMAPINFO*)&bi, DIB_RGB_COLORS);
SelectObject(hdc_memory, hbmp_dst);
delete[] bits;
ReleaseDC(0, hdc);
return 0;
}
else if(Msg == WM_PAINT)
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
BitBlt(hdc, 0, 0, bm.bmWidth, bm.bmHeight, hdc_memory, 0, 0, SRCCOPY);
EndPaint(hWnd, &ps);
return 0;
}
else if(Msg == WM_DESTROY)
{
DeleteDC(hdc_memory);
DeleteObject(hbmp_src);
DeleteObject(hbmp_dst);
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hWnd, Msg, wParam, lParam);
}

Can't draw on custom window frame with DWM

I have created a custom window frame using DWM. The frame extends successfully but whenever I try to draw onto the frame, the extended frame coveres whatever I am trying to draw. I have seen other people try to input a top left within negative bounds, but even when I try to do that, the title bar still overlaps the main window's painting. Here is my code (note: i don't have any code for hit testing):
#include <Windows.h>
#include <numeric>
#include <dwmapi.h>
#pragma comment(lib, "dwmapi.lib")
const auto s_brush = CreateSolidBrush(RGB(0, 0, 255));
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
LRESULT res;
if (DwmDefWindowProc(hwnd, msg, wparam, lparam, &res))
return res;
switch (msg)
{
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_CREATE:
{
RECT r;
GetWindowRect(hwnd, &r);
SetWindowPos(hwnd, 0, 0, 0, r.right - r.left, r.bottom - r.top, SWP_FRAMECHANGED);
}
break;
case WM_ACTIVATE:
{
int metrics[4];
const auto window_dpi_ = GetDpiForWindow(hwnd);
metrics[0] = GetSystemMetricsForDpi(SM_CYCAPTION, window_dpi_);
metrics[1] = GetSystemMetricsForDpi(SM_CXFIXEDFRAME, window_dpi_);
metrics[2] = GetSystemMetricsForDpi(SM_CYSIZEFRAME, window_dpi_);
metrics[3] = GetSystemMetricsForDpi(SM_CYBORDER, window_dpi_);
const auto cy_titlebar_ = std::accumulate(metrics, metrics + sizeof metrics / sizeof(int), 0);
MARGINS margins{ 0, 0, cy_titlebar_, 0 };
DwmExtendFrameIntoClientArea(hwnd, &margins);
}
break;
case WM_PAINT:
{
PAINTSTRUCT ps;
const auto hdc = BeginPaint(hwnd, &ps);
const auto old = SelectObject(hdc, s_brush);
Rectangle(hdc, 0, 0, 50, 75);
SelectObject(hdc, old);
EndPaint(hwnd, &ps);
}
break;
case WM_NCCALCSIZE:
if (wparam == TRUE)
{
RECT& client_rect = reinterpret_cast<LPNCCALCSIZE_PARAMS>(lparam)->rgrc[0];
const auto window_dpi_ = GetDpiForWindow(hwnd);
const auto frame_width{ GetSystemMetricsForDpi(SM_CXFRAME, window_dpi_) };
const auto border_width{ GetSystemMetricsForDpi(SM_CXPADDEDBORDER, window_dpi_) };
const auto frame_height{ GetSystemMetricsForDpi(SM_CYFRAME, window_dpi_) };
client_rect.bottom -= frame_height + border_width;
client_rect.left += frame_width + border_width;
client_rect.right -= frame_width + border_width;
break;
}
default:
return DefWindowProcW(hwnd, msg, wparam, lparam);
}
return 0;
}
int WINAPI wWinMain(HINSTANCE hinstance, HINSTANCE, LPWSTR lpcmdline, int cmd_show)
{
WNDCLASS wc{ CS_HREDRAW | CS_VREDRAW, WndProc, 0, 0, hinstance,
0,0, reinterpret_cast<HBRUSH>(GetStockObject(BLACK_BRUSH)), 0, L"CustWnd" };
const auto hwnd = CreateWindow(MAKEINTATOM(RegisterClass(&wc)), L"Custom Window Frame", WS_OVERLAPPEDWINDOW,
0, 0, 500, 700, 0, 0, hinstance, 0);
ShowWindow(hwnd, cmd_show);
UpdateWindow(hwnd);
MSG msg;
while (GetMessageW(&msg, 0, 0, 0))
{
TranslateMessage(&msg);
DispatchMessageW(&msg);
}
return 0;
}
The window class doesn't have a default cursor, it's going to show the wrong cursors as you move the mouse. Change wc to
WNDCLASS wc{ CS_HREDRAW | CS_VREDRAW, WndProc, 0, 0, hinstance, 0,
LoadCursor(NULL, IDC_ARROW),
reinterpret_cast<HBRUSH>(GetStockObject(BLACK_BRUSH)), 0, L"CustWnd" };
WM_NCHITTEST should also be handled, otherwise title-bar will not grip. It is better to calculate the border thickness based on Windows style, or keep it as static value because it will be needed throughout the procedure, as well as title bar height.
Note that this code will look very different in Windows 10 versus Window 7 which has the weird transparent title-bar, you'll need 32-bit bitmap with alpha channel to draw on title-bar. Or use buffered paint with BufferedPaintSetAlpha as shown below
#include <Windows.h>
#include <Windowsx.h> //for `GET_X_LPARAM` etc.
...
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
static int cy_titlebar_ = 100;
static RECT border_thickness;
LRESULT result;
if(DwmDefWindowProc(hWnd, msg, wParam, lParam, &result))
return result;
switch(msg)
{
case WM_CREATE:
{
//find border thickness
border_thickness = { 0 };
if(GetWindowLongPtr(hWnd, GWL_STYLE) & WS_THICKFRAME)
{
AdjustWindowRectEx(&border_thickness,
GetWindowLongPtr(hWnd, GWL_STYLE) & ~WS_CAPTION, FALSE, NULL);
border_thickness.left *= -1;
border_thickness.top *= -1;
}
else if(GetWindowLongPtr(hWnd, GWL_STYLE) & WS_BORDER)
{
border_thickness = { 1,1,1,1 };
}
MARGINS margins = { 0, 0, cy_titlebar_, 0 };
DwmExtendFrameIntoClientArea(hWnd, &margins);
SetWindowPos(hWnd, NULL, 0, 0, 0, 0,
SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED);
return 0;
}
case WM_NCCALCSIZE:
{
if(wParam)
{
RECT& r = reinterpret_cast<LPNCCALCSIZE_PARAMS>(lParam)->rgrc[0];
r.left += border_thickness.left;
r.right -= border_thickness.right;
r.bottom -= border_thickness.bottom;
return 0;
}
break;
}
case WM_NCHITTEST:
{
result = DefWindowProc(hWnd, msg, wParam, lParam);
if(result == HTCLIENT)
{
POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
ScreenToClient(hWnd, &pt);
if(pt.y < border_thickness.top) return HTTOP;
if(pt.y < cy_titlebar_) return HTCAPTION;
}
return result;
}
case WM_PAINT:
{
PAINTSTRUCT ps;
auto hdc = BeginPaint(hWnd, &ps);
//paint opaque:
RECT rc{ 0, 0, 100, cy_titlebar_ };
BP_PAINTPARAMS params = { sizeof(params), BPPF_NOCLIP | BPPF_ERASE };
HDC memdc;
HPAINTBUFFER hbuffer = BeginBufferedPaint(
hdc, &rc, BPBF_TOPDOWNDIB, &params, &memdc);
auto brush = CreateSolidBrush(RGB(255, 0, 0));
FillRect(memdc, &rc, brush);
DeleteObject(brush);
SetBkMode(memdc, TRANSPARENT);
DrawText(memdc, L"Opaque", -1, &rc, 0);
BufferedPaintSetAlpha(hbuffer, &rc, 255);
EndBufferedPaint(hbuffer, TRUE);
EndPaint(hWnd, &ps);
return 0;
}
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hWnd, msg, wParam, lParam);
}

draw on transparent window using pen

I want to draw on a transparent window using a pen.
When drawing a line black area surround the line.
This image shows the problem:
How to solve this problem?
LRESULT __stdcall WindowProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam)
{
HDC hdc, backDC;
PAINTSTRUCT ps;
static Point prevPt;
// Draw or Erase
static bool isDraw = false;
static bool isErase = false;
// Select Pen Color
static int selectColor = 1;
// Color Pen(R, G, B) and Current Pen
static HPEN redPen;
static HPEN greenPen;
static HPEN bluePen;
static HPEN* currentPen = &redPen;
switch (iMessage)
{
case WM_CREATE:
{
redPen = CreatePen(PS_SOLID, 4, RGB(255, 0, 0));
greenPen = CreatePen(PS_SOLID, 4, RGB(0, 255, 0));
bluePen = CreatePen(PS_SOLID, 4, RGB(0, 0, 255));
return 0L;
}
case WM_DESTROY:
cout << "\n" << "destroying window" << endl;
PostQuitMessage(0);
return 0L;
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
EndPaint(hWnd, &ps);
return 0L;
case WM_LBUTTONDOWN:
prevPt.x = LOWORD(lParam);
prevPt.y = HIWORD(lParam);
isDraw = true;
return 0L;
case WM_LBUTTONUP:
isDraw = false;
return 0L;
case WM_MOUSEMOVE:
{
int x = LOWORD(lParam);
int y = HIWORD(lParam);
if (isDraw)
{
hdc = GetDC(g_hWnd);
HPEN OldPen = (HPEN)SelectObject(hdc, *currentPen);
MoveToEx(hdc, prevPt.x, prevPt.y, NULL);
LineTo(hdc, x, y);
prevPt.x = x;
prevPt.y = y;
DeleteObject(OldPen);
ReleaseDC(g_hWnd, hdc);
}
}
return 0L;
case WM_RBUTTONDOWN:
isErase = true;
return 0L;
case WM_RBUTTONUP:
isErase = false;
return 0L;
case WM_MOUSEWHEEL:
if (selectColor > 3)
selectColor = 1;
if (selectColor == 1) // Red
currentPen = &redPen;
else if (selectColor == 2)
currentPen = &greenPen;
else if (selectColor == 3)
currentPen = &bluePen;
selectColor++;
return 0L;
}
return DefWindowProc(hWnd, iMessage, wParam, lParam);
}
void main()
{
HWND window;
LPCWSTR myclass = L"DrawTest";
WNDCLASSEX wndclass = { sizeof(WNDCLASSEX), CS_VREDRAW | CS_HREDRAW, WindowProc,
0, 0, NULL, LoadIcon(0,IDI_APPLICATION), LoadCursor(0,IDC_ARROW), (HBRUSH)WHITE_BRUSH, 0, myclass, LoadIcon(0,IDI_APPLICATION) };
if (RegisterClassEx(&wndclass))
{
window = CreateWindowEx(WS_EX_TRANSPARENT, myclass, L"title", WS_POPUP, 0, 0, GetSystemMetrics(SM_CXFULLSCREEN), GetSystemMetrics(SM_CYFULLSCREEN), 0, 0, NULL, 0);
}
VideoCapture* pCapture = nullptr;
pCapture = new VideoCapture(0);
if (pCapture)
{
if (!pCapture->isOpened())
{
cout << "Can not open video file." << endl;
return;
}
int fps = (int)(pCapture->get(CAP_PROP_FPS));
int delay = 0;
if (fps == 0)
fps = 24;
delay = 1000 / fps;
Mat colorMat;
while (1)
{
*pCapture >> colorMat;
if (colorMat.empty())
break;
Mat copyColor;
colorMat.copyTo(copyColor);
imshow("colorMat", copyColor);
int ckey = waitKey(delay);
if (ckey == 27)
break;
if (window)
{
ShowWindow(window, SW_SHOW);
MSG msg;
if (PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE))
{
GetMessage(&msg, 0, 0, 0);
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
}
cv::destroyAllWindows();
}
}
As I said in my comment, create a layered window:
window = CreateWindowEx(WS_EX_LAYERED, myclass, L"title", WS_POPUP, 0, 0,
GetSystemMetrics(SM_CXFULLSCREEN), GetSystemMetrics(SM_CYFULLSCREEN),
HWND_DESKTOP, NULL, NULL, NULL);
set color transparency the same as your background brush:
SetLayeredWindowAttributes(window, RGB(255, 255, 255), 0, LWA_COLORKEY);
In WM_PAINT
hdc = BeginPaint(hwnd, &ps);
HPEN OldPen = (HPEN)SelectObject(hdc, *currentPen);
//set random values
MoveToEx(hdc, 50, 50, NULL);
LineTo(hdc, 450, 450);
SelectObject(hdc, OldPen);
EndPaint(hwnd, &ps);
return 0;
This code works, BUT you cant get mouse messages cause the window is transparent. That is the main issue, not the drawing.
EDIT
The problem is how to get mouse messages. The solution is to create a second window on top of your main window with opacity nearly zero so it is not visible but get the mouse messages!
window = CreateWindowEx(WS_EX_LAYERED, myclass, L"title", WS_POPUP, 0, 0,
GetSystemMetrics(SM_CXFULLSCREEN), GetSystemMetrics(SM_CYFULLSCREEN),
HWND_DESKTOP, NULL, NULL, NULL);
windowClone = CreateWindowEx(WS_EX_LAYERED, myclass, L"title", WS_POPUP, 0, 0,
GetSystemMetrics(SM_CXFULLSCREEN), GetSystemMetrics(SM_CYFULLSCREEN),
window, NULL, NULL, NULL);
Make your main window complete transparent:
//background color MUST be the same with color Key!
SetLayeredWindowAttributes(window, RGB(255, 255, 255), 0, LWA_COLORKEY);
Make nearly transparent your clone window
//The transparency is set to 1
SetLayeredWindowAttributes(windowClone, 0, 1, LWA_ALPHA);
LRESULT CALLBACK WindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam){
PAINTSTRUCT ps;
HDC hdc;
static int draw = FALSE, startX, startY, endX, endY, posX, posY;
switch(message){ //handle the messages
case WM_PAINT:
printf("WM_PAINT \n");
if( hwnd == window && draw == TRUE ){
HPEN OldPen, redPen;
redPen = CreatePen(PS_SOLID, 4, RGB(255, 0, 0));
hdc = BeginPaint(hwnd, &ps);
OldPen = (HPEN)SelectObject(hdc, redPen);
MoveToEx(hdc, startX, startY, NULL);
LineTo(hdc, endX, endY);
SelectObject(hdc, OldPen);
EndPaint(hwnd, &ps);
DeleteObject(redPen);
return 0;
}
break;
case WM_MOUSEMOVE:
//printf("WM_MOUSEMOVE \n");
if( hwnd == windowClone && draw == TRUE ){
startX = posX;
startY = posY;
endX = GET_X_LPARAM(lParam);
endY = GET_Y_LPARAM(lParam);
posX = endX;
posY = endY;
InvalidateRect(window, NULL, FALSE);
}
break;
case WM_LBUTTONDOWN:
printf("WM_LBUTTONDOWN \n");
if( hwnd == windowClone ){
posX = GET_X_LPARAM(lParam);
posY = GET_Y_LPARAM(lParam);
draw = TRUE;
}
break;
case WM_LBUTTONUP:
printf("WM_LBUTTONUP \n");
if( hwnd == windowClone && draw == TRUE ){
draw = FALSE;
}
break;
case WM_CAPTURECHANGED:
printf("WM_CAPTURECHANGED \n");
if( hwnd == windowClone && draw == TRUE ){
draw = FALSE;
}
break;
default: //for messages that we don't deal with
return DefWindowProc(hwnd, message, wParam, lParam);
}
return DefWindowProc(hwnd, message, wParam, lParam);
}

How to make a window with a glass background?

I'm trying to make a window with a glass background, but it's not working. See my code:
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
switch (message) {
case WM_ERASEBKGND: {
RECT rect;
GetClientRect(hWnd, &rect);
FillRect(GetDC(hWnd), &rect, (HBRUSH)GetStockObject(BLACK_BRUSH));
return(0);
} case WM_PAINT: {
RECT rect;
GetClientRect(hWnd, &rect);
rect.bottom = 262;
FillRect(GetDC(hWnd), &rect, (HBRUSH)COLOR_WINDOW);
return(0);
} case WM_CREATE: {
if (IsWindowsVistaOrGreater()) {
BOOL IsCompositionEnabled = FALSE;
DwmIsCompositionEnabled(&IsCompositionEnabled);
if (IsCompositionEnabled) {
MARGINS margins = {0, 0, 0, 0};
margins.cyBottomHeight = 100;
HRESULT hr = DwmExtendFrameIntoClientArea(hWnd, &margins);
if (SUCCEEDED(hr)) {
}
}
}
return(0);
} case WM_CLOSE: {
DestroyWindow(hWnd);
return(0);
} case WM_DESTROY: {
PostQuitMessage(0);
return(0);
} default: {
return(DefWindowProc(hWnd, message, wParam, lParam));
}
}
}
This code makes the following window: See the image
This window is what I'm trying to do but there's a problem. When I move the window it blinks. Why does it blink?
There are a few things you should change:
When you handle WM_PAINT, you should call BeginPaint to get the DC and other info for your painting, then call EndPaint when you are done. This gives you a DC that restricts your painting to the clipping region needed, and prevents the flicker.
case WM_PAINT: {
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
RECT rect;
GetClientRect(hWnd, &rect);
rect.bottom = 262;
FillRect(hdc, &rect, (HBRUSH)COLOR_WINDOW);
EndPaint(hWnd, &ps);
return(0);
}
You should also return 1 from WM_ERASEBKGND as you have done the erasing.
The HDC to use when erasing is passed in wParam so use that rather than the window DC.
case WM_ERASEBKGND: {
RECT rect;
GetClientRect(hWnd, &rect);
FillRect((HDC)(wParam), &rect, (HBRUSH)GetStockObject(BLACK_BRUSH));
return(1);
}