My problem is that my button has a background color for some reason, and I do not know why. I do not put the desktop background in the entire area of the button.
case WM_CREATE:
{
hwndButton = CreateWindowEx(0, L"BUTTON", L"Some static text",
WS_CHILD | WS_VISIBLE | BS_OWNERDRAW,
25, 125, 300, 300, hWnd, 0, 0, 0);
}
case WM_DRAWITEM:
{
//RECT r;
LPDRAWITEMSTRUCT lpDIS = (LPDRAWITEMSTRUCT)lParam;
if (hwndButton == lpDIS->hwndItem) {
SetBkColor(lpDIS->hDC, RGB(0, 255, 0));
//FillRect(lpDIS->hDC,&r,CreateSolidBrush(RGB(100,100,200)));
SetTextColor(lpDIS->hDC, RGB(100, 0, 100));
WCHAR staticText[99] = L"test";
TextOut(lpDIS->hDC, lpDIS->rcItem.left, lpDIS->rcItem.top, staticText, 10);
}
Your code only draws as much of the button background as the text requires, use ExtTextOut and specify ETO_OPAQUE to fill the entire space. Either that or use FillRect to actually draw the button background and use ExtTextOut without ETO_OPAQUE to draw with a transparent background.
Related
I have a window, which I want it to behave like a toggle button. Once clicked it will add 4px border and clicking after will make the border disappear. I figured how to make the window behave like a toggle button using BS_PUSHLIKE and Button_SetCheck() but can't seem to figure out how to adjust the border size for this window.
Thanks to all who take their time to help
Maybe you can use MoveWindow to resize the window, and then draw the border yourself, like this,
Draw a borderless window first:
HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
100, 100, 800, 600, nullptr, nullptr, hInstance, nullptr);
LONG lStyle = GetWindowLong(hWnd, GWL_STYLE);
lStyle &= ~(WS_CAPTION | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_SYSMENU);
SetWindowLong(hWnd, GWL_STYLE, lStyle);
Then handle the window border in the WM_LBUTTONDOWN message:
int num = 0;
case WM_LBUTTONDOWN:
{
RECT rcWind;
HDC dc = GetDC(hWnd);
GetWindowRect(hWnd, &rcWind);
if (num >= 0)
{
num--;
RECT rcClient;
MoveWindow(hWnd, rcWind.left - 4, rcWind.top - 4, 8 + rcWind.right - rcWind.left, 8 + rcWind.bottom - rcWind.top, TRUE);
GetClientRect(hWnd, &rcClient);
HPEN hPen = CreatePen(PS_SOLID, 4, RGB(255, 128, 1));
HGDIOBJ hOldPen = SelectObject(dc, hPen);
Rectangle(dc, rcClient.left, rcClient.top, rcClient.right, rcClient.bottom);
DeleteObject(hPen);
}
else if (num < 0)
{
MoveWindow(hWnd, rcWind.left + 4, rcWind.top + 4, rcWind.right - rcWind.left - 8, rcWind.bottom - rcWind.top - 8, TRUE);
num++;
}
}
break;
I am looking at this sample https://learn.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-createfonta of CreateFont API
It clearly says that after the font been created with CreateFont it should be destroyed by DeleteObject call. DeleteObject(hFont); is only called once. CreateFont is called 3 times. Is this a bug in the MS docs? Shouldn't the old font be stored by retrieving it with SelectObject and set back after new fonts been used?
Yes, two of the created font objects are leaked.
Note that MS sample code is generally poor about error handling and object cleanup (they generally focus on demonstrating whatever is central to the sample - here the CreateFont call - while ignoring or minimizing those issues).
The example in the documentation did cause the leak of the font object
I built a sample as follows:
#include <Windows.h>
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int WINAPI WinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPSTR szCmdLine, _In_ int iCmdShow)
{
static TCHAR szAppName[] = TEXT("hello windows");
HWND hwnd;
MSG msg;
WNDCLASS wndclass;
wndclass.style = CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc = WndProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = hInstance;
wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = szAppName;
if (!RegisterClass(&wndclass))
{
MessageBox(NULL, TEXT("This program requires Windows NT!"), szAppName, MB_ICONERROR);
}
hwnd = CreateWindow(szAppName,
TEXT("the hello program"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
hInstance,
NULL);
ShowWindow(hwnd, iCmdShow);
UpdateWindow(hwnd);
while (GetMessageW(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessageW(&msg);
}
return msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
PAINTSTRUCT ps;
HDC hdc;
switch (message)
{
case WM_PAINT:
{
RECT rect;
HBRUSH hBrush;
HFONT hFont;
hdc = BeginPaint(hWnd, &ps);
//Logical units are device dependent pixels, so this will create a handle to a logical font that is 48 pixels in height.
//The width, when set to 0, will cause the font mapper to choose the closest matching value.
//The font face name will be Impact.
hFont = CreateFont(48, 0, 0, 0, FW_DONTCARE, FALSE, TRUE, FALSE, DEFAULT_CHARSET, OUT_OUTLINE_PRECIS,
CLIP_DEFAULT_PRECIS, CLEARTYPE_QUALITY, VARIABLE_PITCH, TEXT("Impact"));
SelectObject(hdc, hFont);
//Sets the coordinates for the rectangle in which the text is to be formatted.
SetRect(&rect, 100, 100, 700, 200);
SetTextColor(hdc, RGB(255, 0, 0));
DrawText(hdc, TEXT("Drawing Text with Impact"), -1, &rect, DT_NOCLIP);
//DeleteObject(hFont);
//Logical units are device dependent pixels, so this will create a handle to a logical font that is 36 pixels in height.
//The width, when set to 20, will cause the font mapper to choose a font which, in this case, is stretched.
//The font face name will be Times New Roman. This time nEscapement is at -300 tenths of a degree (-30 degrees)
hFont = CreateFont(36, 20, -300, 0, FW_DONTCARE, FALSE, TRUE, FALSE, DEFAULT_CHARSET, OUT_OUTLINE_PRECIS,
CLIP_DEFAULT_PRECIS, CLEARTYPE_QUALITY, VARIABLE_PITCH, TEXT("Times New Roman"));
SelectObject(hdc, hFont);
//Sets the coordinates for the rectangle in which the text is to be formatted.
SetRect(&rect, 100, 200, 900, 800);
SetTextColor(hdc, RGB(0, 128, 0));
DrawText(hdc, TEXT("Drawing Text with Times New Roman"), -1, &rect, DT_NOCLIP);
//DeleteObject(hFont);
//Logical units are device dependent pixels, so this will create a handle to a logical font that is 36 pixels in height.
//The width, when set to 10, will cause the font mapper to choose a font which, in this case, is compressed.
//The font face name will be Arial. This time nEscapement is at 250 tenths of a degree (25 degrees)
hFont = CreateFont(36, 10, 250, 0, FW_DONTCARE, FALSE, TRUE, FALSE, DEFAULT_CHARSET, OUT_OUTLINE_PRECIS,
CLIP_DEFAULT_PRECIS, ANTIALIASED_QUALITY, VARIABLE_PITCH, TEXT("Arial"));
SelectObject(hdc, hFont);
//Sets the coordinates for the rectangle in which the text is to be formatted.
SetRect(&rect, 500, 200, 1400, 600);
SetTextColor(hdc, RGB(0, 0, 255));
DrawText(hdc, TEXT("Drawing Text with Arial"), -1, &rect, DT_NOCLIP);
DeleteObject(hFont);
EndPaint(hWnd, &ps);
break;
}
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
Start the task manager after running the sample, you can see it in details:
Then trigger a WM_PAINT message:
We can find that its GDI Objects has increased by 2, and it will increase every time it is triggered, so this example will cause object leakage.
When we call DeleteObject(hFont); after each use(In line 75 and line 88 of my sample), and repeat the above steps, we will find that GDI Objects will not increase, thus solving the problem of object leakage.
I specify a font and its size for my listview items using win32 api and it works properly in Windows Xp. I install it in Windows 7 and see size of fonts are too small and hard to read although i specified 17 for its size.
I increased default font sizes in Windows 7 but still the fonts in my program are too small.
This is the code that i specify font for the listview items inside Window procedure :
case WM_DRAWITEM:
{
LPDRAWITEMSTRUCT pDIS=(LPDRAWITEMSTRUCT)lParam;
HDC hDC=pDIS -> hDC;
RECT rc = pDIS -> rcItem;
HBRUSH bg = (HBRUSH) (::GetStockObject(DC_BRUSH));
HPEN pn=(HPEN)(::GetStockObject(NULL_PEN));
::SelectObject( hDC , bg );
::SelectObject( hDC , pn );
::SetTextColor( hDC , RGB(0,0,0));
HFONT hF;
hF=CreateFont(17, 0, 0, 0, FW_DONTCARE, FALSE, FALSE, FALSE, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_SWISS, L"Tahoma");
HFONT hOldFont = (HFONT) SelectObject(hDC, hF);
if( (pDIS->itemID % 2) != 0 )
::SetDCBrushColor(hDC, RGB(255,255,255));
else{
::SetDCBrushColor(hDC, RGB(223, 241, 255));
}
::Rectangle( hDC , rc.left , rc.top , rc.right , rc.bottom );
char buffer[1000] = {0};
ListView_GetItemText(pDIS -> hwndItem, pDIS -> itemID, 0, (LPWSTR)buffer, 1000);
::DrawText(hDC, (LPWSTR)buffer, -1, &rc, DT_SINGLELINE | DT_VCENTER);
SelectObject(hDC, hOldFont);
DeleteObject(hF);
}
break;
How can i make Windows display my desired font size and not that small font?
Thanks!
Use SystemParametersInfo to find the default font as follows:
NONCLIENTMETRICS metrics;
metrics.cbSize = sizeof(NONCLIENTMETRICS);
::SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS),
&metrics, 0);
hfont = CreateFontIndirect(&metrics.lfMessageFont);
Use .lfMessageFont for ListView and other child controls.
This will retrieve the correct font name and font size.
This font size is already adjusted for DPI settings of system and application.
You can create this font once during windows creation. Then assign it as the main font for the window and listview control. This will update the header control for the listview.
HFONT hfont;
...
case WM_CREATE:
{
if (!hfont)
{
NONCLIENTMETRICS metrics;
metrics.cbSize = sizeof(NONCLIENTMETRICS);
::SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS),
&metrics, 0);
hfont = CreateFontIndirect(&metrics.lfMessageFont);
}
hListView = CreateWindow(WC_LISTVIEW ...);
SendMessage(hWnd, WM_SETFONT, (WPARAM)hfont, MAKELPARAM(TRUE, 0));
SendMessage(hListView, WM_SETFONT, (WPARAM)hfont, MAKELPARAM(TRUE, 0));
...
break;
}
Also, do not use (LPWSTR) cast to hide compiler warnings and errors. Use casting only when you are sure it's applicable. In this case, char and wchar_t are very different storage types, casting may in some special cases, but it's far from reliable.
char buffer[1000] creates a buffer of size 1000 bytes. But you are making a call to ListView_GetItemText to read 1000 Unicode characters, which in this case is 2000 bytes and results in buffer overrun. You can change as follows:
case WM_DRAWITEM:
{
LPDRAWITEMSTRUCT pDIS = (LPDRAWITEMSTRUCT)lParam;
HDC hDC = pDIS->hDC;
RECT rc = pDIS->rcItem;
COLORREF textcolor = RGB(0, 0, 0);
COLORREF bkcolor = RGB(255, 255, 255);
if((pDIS->itemID % 2) == 0)
{
bkcolor = RGB(223, 241, 255);
}
if(pDIS->itemState & ODS_SELECTED)
{
textcolor = RGB(255, 255, 255);
bkcolor = RGB(0, 0, 255);
}
SetDCBrushColor(hDC, bkcolor);
SelectObject(hDC, GetStockObject(DC_BRUSH));
SelectObject(hDC, GetStockObject(NULL_PEN));
SetTextColor(hDC, textcolor);
Rectangle(hDC, rc.left, rc.top, rc.right, rc.bottom);
auto oldfont = SelectObject(hDC, hfont);
wchar_t buffer[1000] = { 0 };
ListView_GetItemText(pDIS->hwndItem, pDIS->itemID, 0, buffer, 1000);
DrawText(hDC, buffer, -1, &rc, DT_SINGLELINE | DT_VCENTER);
SelectObject(hDC, oldfont);
return TRUE;
}
*hfont is not destroyed in above window procedure. It should be cleaned up elsewhere.
I am using Window 7 and I wanted to add a transparent border to my window. The same border as we can see on skype for instance.
Window Creation:
hWnd = CreateWindow(L"Example", 0, WS_POPUP, 100, 100, 400, 500, NULL, NULL, hinst, NULL);
Is there a way to add the transparent border to WS_POPUP window without the WS_SYSMENU?
I have a window with a background image and I want to create a panel (like in .NET) with a white border and a semi-transparent background RGBA(255, 255, 255, 124), so the image in the background could be also visible. Should I use STATIC control or a child window for that? I know that in order to set the RGBA color of a window I have to use SetLayeredWindowAttributes, but I don't know if that would work with STATIC control.
What type of control is used normally for this and what WINAPI functions could I use to set the border thickness and color?
Thanks
SOME CODE:
// Create the static control (inside the WM_CREATE of the parent window)
hPanel = CreateWindowEx(
WS_EX_TRANSPARENT,
L"STATIC",
L"",
WS_CHILD | WS_VISIBLE | SS_WHITEFRAME,
10, 90,
200, 120,
hWnd,
(HMENU)IDC_PANEL,
hInstance,
NULL);
// Trying to set the alpha level
SetWindowLong(hPanel , GWL_EXSTYLE,
GetWindowLong(hPanel , GWL_EXSTYLE) | WS_EX_LAYERED);
SetLayeredWindowAttributes(hPanel , 0, (255 * 70) / 100, LWA_ALPHA);
// Changing the background color of the STATIC in WM_CTLCOLORSTATIC
case WM_CTLCOLORSTATIC:
hStatic = (HDC)wParam;
switch (GetDlgCtrlID((HWND)lParam)) {
case IDC_PANEL:
SetTextColor(hStatic, RGB(255, 255, 255));
SetBkColor(hStatic, RGB(26, 127, 231));
break;
default:
SetTextColor(hStatic, RGB(255, 255, 255));
SetBkMode (hStatic, TRANSPARENT);
}
return (LRESULT)GetStockObject(NULL_BRUSH);
break;
So, the only thing I get with this code is a transparent bordered control. I don't get the background color and the alpha effect.