Color of the lines are not changing? - c

I want to draw a white line in my window:
case WM_PAINT:
{
hdc=GetDC(hWnd);
SelectObject(hdc, GetStockObject(WHITE_BRUSH));
MoveToEx(hdc, 0, 0, 0);
LineTo(hdc, 100, 100);
ReleaseDC(hWnd, hdc);
}
but the color is still black. What's Wrong?

You are trying to set a brush for your line when you should be using a pen. A brush is used to fill the interior of a shape while a pen is used to draw the lines.
MSDN says this about pens:
A pen is a graphics tool that an application can use to draw lines and
curves. Drawing applications use pens to draw freehand lines, straight
lines, and curves.
And this about brushes:
A brush is a graphics tool that applications use to paint the interior
of polygons, ellipses, and paths.
Your code would need to be something more like this:
case WM_PAINT:
{
PAINTSTRUCT ps;
hdc=BeginPaint(hWnd, &ps); // Used instead of GetDC in WM_PAINT
HPEN hPen = CreatePen(PS_SOLID, 1, RGB(255,255,255));
HPEN hOldPen = SelectObject(hdc, hPen);
MoveToEx(hdc, 0, 0, 0);
LineTo(hdc, 100, 100);
SelectObject(hdc, hOldPen);
DeleteObject(hPen);
EndPaint(hWnd, &ps); // Used instead of ReleaseDC in WM_PAINT
}

Related

Making some parts of the window transparent in WinAPI

I want to make only certain(rectangular) parts of the window transparent.
I have set the window as WS_EX_LAYERED and the WM_PAINT function is as follows:
case WM_PAINT:;
RECT rect;
GetWindowRect(hwnd, &rect);
HDC hdc = GetDC(hwnd);
HDC hdc1 = CreateCompatibleDC(hdc);
HBITMAP hBitmap = CreateCompatibleBitmap(hdc, rect.right - rect.left, rect.bottom - rect.top);
SelectObject(hdc, hBitmap);
SIZE size = {rect.right - rect.left, rect.bottom - rect.top};
BLENDFUNCTION blendFunc = {AC_SRC_OVER, 0, 0, AC_SRC_ALPHA};
UpdateLayeredWindow(hwnd, hdc1, NULL, &size, hdc, NULL, RGB(0, 0, 0), &blendFunc, ULW_ALPHA);
DeleteObject(hBitmap);
DeleteDC(hdc);
ReleaseDC(hwnd, hdc1);
break;
I tried creating a child window, but that doesn't seem to work if I change it's opacity through SetLayeredWindowAttributes, possibly because it mimics the parent windows opacity. I am currently trying to use UpdateLayeredWindow to make certain parts transparent, but I can't even make the entire part transparent using UpdateLayeredWindow.
What is the general way to make certain parts of the window transparent?
I suggest you could refer to the Doc:Using Layered Windows
To have a dialog box come up as a translucent window, first create the
dialog as usual. Then, on WM_INITDIALOG, set the layered bit of the
window's extended style and call SetLayeredWindowAttributes with the
desired alpha value.
The third parameter of SetLayeredWindowAttributes is a value that ranges from 0 to 255, with 0 making the window completely transparent and 255 making it completely opaque.
In order to use layered child windows, the application has to declare itself Windows 8-aware in the manifest. Refer to the thread: How to use WS_EX_LAYERED on child controls

WINAPI: Window client area not lining up with the window

The client area of my window is not aligning properly with the outer non-client area. Take a look, this is when I am not touching the window, just after I launch it:
It's not aligned, although all dimensions across all functions are ok, 500x500 to be exact.
Now, when I resize it, it kind of aligns correctly:
HWND Window = CreateWindowEx(
0,
WindowClass.lpszClassName,
"Handmade Hero",
WS_OVERLAPPED | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_VISIBLE,
CW_USEDEFAULT,
CW_USEDEFAULT,
500,
500,
0,
0,
Instance,
0);
RECT rect;
GetClientRect(Window, &rect);
Win32AllocateMemoryBuffer(&GlobalBackBuffer, rect.right, rect.bottom);
Message handling:
case WM_PAINT:
{
PAINTSTRUCT Paint;
HDC DeviceContext = BeginPaint(Window, &Paint);
Dimension rect;
GetClientRect(Window, &rect);
Win32DisplayBufferInWindow(DeviceContext, &GlobalBackBuffer, Dimension.right, Dimension.bottom);
EndPaint(Window, &Paint);
} break;
The stretchdbits:
StretchDIBits(DeviceContext,
0, 0, WindowWidth, WindowHeight,
0, 0, Buffer->BitmapWidth, Buffer->BitmapHeight,
Buffer->BitmapMemory,
&Buffer->BitmapInfo,
DIB_RGB_COLORS, SRCCOPY);
I've been tracking the dimensions across all the program in VS debugger, but couldn't track the problem. Maybe your intuition would spot something?

Draw a line next to word in WinAPI

How do I draw a line like this that is right next to a word like "Counts", in WinAPI with C?
Using Dialog Resources
Create a static text control with no text that is 1 or 2 pixels in height, turn on the border (WS_BORDER), and set its style to Static Edge (WS_EX_STATICEDGE). Then create a static text control with the word "Counts" in it on top of that. Then use CreateDialog() or DialogBox() to show the dialog box.
IDD_DIALOG1 DIALOGEX 0, 0, 172, 63
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Dialog"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
LTEXT "",IDC_STATIC,6,12,156,1,WS_BORDER,WS_EX_STATICEDGE
LTEXT "Counts ",IDC_STATIC,6,8,26,8
END
Note: This is verbatim what Visual Studio generated using the dialog designer.
Creating Static Controls Using CreateWindow() (as suggested by Jonathan Potter)
LRESULT OnCreate( HWND hWnd, LPCREATESTRUCT lpCreateStruct )
{
// Get default gui font
NONCLIENTMETRICS metrics;
metrics.cbSize = sizeof(NONCLIENTMETRICS);
SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &metrics, NULL);
HFONT hFont = CreateFontIndirect(&metrics.lfMessageFont);
// Create the line
CreateWindowEx(WS_EX_STATICEDGE, _T("STATIC"), NULL, WS_CHILD|WS_VISIBLE|WS_BORDER,
10, 17, 280, 1, hWnd, NULL, lpCreateStruct->hInstance, NULL);
// Create the Counts label
HWND hwndCounts = CreateWindow(_T("STATIC"), _T("Counts "), WS_CHILD|WS_VISIBLE,
10, 10, 50, 26, hWnd, NULL, lpCreateStruct->hInstance, NULL);
// Apply the default gui font
SendMessage(hwndCounts, WM_SETFONT, (WPARAM)hFont, TRUE);
// Cleanup the font object
DeleteObject(hFont);
}
Drawing manually on the WM_PAINT event
void OnPaint( HWND hWnd )
{
// Get the default font
NONCLIENTMETRICS metrics;
metrics.cbSize = sizeof(NONCLIENTMETRICS);
SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &metrics, NULL);
HFONT hFont = CreateFontIndirect(&metrics.lfMessageFont);
// Setup HDC
RECT rect;
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
// Select the default font
SelectObject(hdc, hFont);
// Draw the line using the button shadow
SelectObject(hdc, GetStockObject(DC_PEN));
SetDCPenColor(hdc, GetSysColor(COLOR_BTNSHADOW));
MoveToEx(hdc, 10, 17, NULL);
LineTo(hdc, 280, 17);
// Draw the word Counts overtop of the line
SetRect(&rect, 10, 10, 280, 22);
SetTextColor(hdc, GetSysColor(COLOR_BTNTEXT));
SetBkColor(hdc, GetSysColor(COLOR_BTNFACE));
DrawText(hdc, TEXT("Counts "), -1, &rect, DT_NOCLIP);
// Cleanup the font object
DeleteObject(hFont);
// Quit painting
EndPaint(hWnd, &ps);
}
Note: Something I did not account for in this example is the height of the default font. You will want to adjust the code for that.
Here is a screenshot of the output of this method.
In your example, it looked like a single one pixel line, so that's what I drew, but if you'd like to make the line look more like a 'Fixed 3D' or 'lowered bevel line' (which is what the group box tends to draw for it's border line), then you can draw another line below it with the button highlight color.
SetDCPenColor(hdc, GetSysColor(COLOR_BTNHIGHLIGHT));
MoveToEx(hdc, 10, 18, NULL);
LineTo(hdc, 280, 18);
As pointed out by Ben Voigt, it might be better to do this with DrawEdge though.
RECT line;
SetRect(&line, 10, 17, 280,17);
DrawEdge(hdc, &line, EDGE_ETCHED, BF_TOP );
Creating a Group Box Control (suggested by Hans Passant)
Hans Passant's suggestion of doing this with a Group Box did work when I tested it. It still drew a rectangle, and when you enabled visual styles it was very difficult to see. Nevertheless, this should get you started if you want to give it a go.
HWND hwndGroup = CreateWindow(_T("Button"), _T("Counts "),
WS_CHILD|WS_VISIBLE|BS_GROUPBOX, 10, 10, 280, 2, hWnd, NULL,
lpCreateStruct->hInstance, NULL);
SendMessage(hwndGroup, WM_SETFONT, (WPARAM)hFont, TRUE);
Additional Note
Something else I would like to suggest is that you use can use Spy++ which comes with Visual Studio to analyze the window you are looking at. This will tell you at the very least if it's a child control, or whether they are painting it manually. If it's a child control you will also be able to see the rectangle and styles that are applied to it, as well lots of additional information.

SetBkMode(hdc, TRANSPARENT) doesn't work

When I use SetBkMode(hdc, TRANSPARENT); in the code below, I got the following effect when I resize the main window (and hence when the child receives the WM_PAINT message):
The problem is : When I resize the main window, The old area of "Find:" shoule be erased, I guess. But it just remains there.
If I don't use SetBkMode(hdc, TRANSPARENT);, I don't have this problem. It looks like:
, i.e it has white background. Furthermore, if I use SetBkMode(hdc, TRANSPARENT);, it looks like the same as above, before I resize the main window. So I don't think SetBkMode(hdc, TRANSPARENT); works here.
the hwnd is a static child with style SS_BITMAP.
Do you know why this issue occurs?
switch (message) {
case WM_PAINT:
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
SelectObject(hdc, gDefaultGuiFont);
SetBkMode(hdc, TRANSPARENT);
RECT rc;
GetClientRect(hwnd, &rc);
DrawText(hdc, _TR("Find:"), -1, &rc, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
EndPaint(hwnd, &ps);
return 0;
.............
}
Try to use "fixed" rectangles. For example
RECT rc;
GetClientRect(hwnd, &rc);
rc.left += ...; rc.top += ...; // shift up-left point
DrawText(hdc, _TR("Find:"), -1, &rc, DT_SINGLELINE | DT_LEFT | DT_TOP);
The idea is you draw text in wrong position (once) and in right position (twice) while backgound updated only once. Can't say more on part of code.
The problem is that windows is not updating the control (in time) that's behind your static control, you are now responsible for it's contents. So you want to use the background provided by the parent. Well just ask the parent to draw it for you in the child window:
RECT rc;
GetClientRectRelative(m_hWnd, GetParent(m_hWnd), &rc);
SetWindowOrgEx(m_mdc, rc.left, rc.top, NULL);
SendMessage(GetParent(m_hWnd), WM_PAINT, (WPARAM)(HDC)m_mdc);
SetWindowOrgEx(m_mdc, 0, 0, NULL);
In which
bool GetClientRectRelative(HWND hWnd, HWND hWndRelativeTo, RECT *pRect)
{
RECT rcWnd, rcRelativeTo;
if (!GetClientRect(hWnd, &rcWnd) ||
!ClientToScreen(hWnd, (POINT*)&rcWnd) ||
!ClientToScreen(hWnd, (POINT*)&rcWnd + 1) ||
!GetClientRect(hWndRelativeTo, &rcRelativeTo) ||
!ClientToScreen(hWndRelativeTo, (POINT*)&rcRelativeTo) ||
!ClientToScreen(hWndRelativeTo, (POINT*)&rcRelativeTo + 1))
return false;
pRect->top = rcWnd.top - rcRelativeTo.top;
pRect->left = rcWnd.left - rcRelativeTo.left;
pRect->right = rcWnd.right - rcRelativeTo.left;
pRect->bottom = rcWnd.bottom - rcRelativeTo.top;
return true;
}
Now draw anything you like, I suggest you'd use the TRANSPARENT background mode.
Please create all your child windows with the styles WS_CLIPCHILDREN and WS_CLIPSIBLINGS, then these problems will become apparent immediately and you avoid flicker.

Creating and using fonts / avoiding memory leaks in windows GDI

I'm trying to get to the bottom of a memory leak in an application written in C and running on Windows CE 6.0. I suspect that the issue MAY be related to the handling of the paint event of the window. In pseudo code it looks like this.
LRESULT CALLBACK HandlePaint(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam)
{
HDC hdc;
PAINTSTRUCT ps;
hdc = BeginPaint (hWnd, &ps);
HFONT logfont;
FONTINFO font1, font2;
memset(&logfont, 0, sizeof(LOGFONT));
//set font options for font1.
font1 = CreateFontIndirect(&logfont);
memset(&logfont, 0, sizeof(LOGFONT));
//set font options for font2.
font2 = CreateFontIndirect(&logfont);
for(int i = 0; i <= SOME_NUMBER; i++)
{
DrawStuff(hdc, font1);
DrawStuff(hdc, font2);
}
EndPaint (hWnd, &ps);
}
INT DrawStuff(HDC hdc, HFONT font)
{
HPEN pen = CreatePen(PS_SOLID, borderWidth, bordercolor);
HBRUSH brush = CreateSolidBrush(backcolor);
SelectObject (hdc, pen);
SelectObject (hdc, brush);
SelectObject(hdc, font);
SetTextColor (hdc, forecolor);
SetBkColor (hdc, backcolor);
DrawText (hdc, pChar, wcslen(pChar), prect, DT_CENTER|DT_VCENTER|DT_SINGLELINE|DT_NOPREFIX);
DeleteObject(font);
DeleteObject(brush);
DeleteObject(pen);
}
I've noticed in the examples I've seen for windows graphics that there seems to be a pattern for most grapics objects of:
HBRUSH brush = CreateBrush();
SelectObject(hdc, brush);
// use brush
DeleteObject(brush);
However, as you can see in the example above with the fonts, each font is being created once, and then Selected/Deleted multiple times. I'm not sure what the implications are of doing that. Would there be a reason to suspect a memory leak here?
Thanks!
I agree with #pmg's comment that the creator of the Form should be the destroyer of the font, not the DrawStuff callee.
Also bear in mind that SelectObject returns the original item in the DC and you should always return that object when you're done, e.g.:
HPEN newPen = CreatePen(...);
HPEN oldPen = SelectObject(hdc, newPen);
// do stuff
// clean up
SelectObject(hdc, oldPen); // <-- note this line
DeleteObject(newPen);

Resources