Draw Shapes in WinAPI C++ - winapi

I'm studying Drawing Shapes by WinAPI C++
I tried to draw 2 ellipse with some codes on WM_PAINT:
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
HPEN hPen = CreatePen(PS_DASHDOTDOT, 2, NULL);SelectObject(hdc, hPen);
Ellipse(hdc, 100, 200, 400, 400);
Ellipse(hdc, 300, 300, 500, 510);
DeleteObject(hPen);
EndPaint(hWnd, &ps);
But the output is:
The result I expect is neither shapes is front of the other. And the border is dash dot dot.
Can anyone show me my mistake? I appreciate for your help.

Ellipse() (like all GDI shape functions) fills the shape using the current brush, which is why your output looks like that. For details on that see setting pen and brush colors.
If you want just the ellipse with no fill, first select a null brush:
SelectObject( hdc, GetStockObject( NULL_BRUSH ) );

One appears on top of the other because you're not just drawing the outline, but filling it as well. To stop filling it, you can select a "hollow brush", sometimes called a "null brush".
HBRUSH hbrOld = SelectObject(hdc, GetStockObject(HOLLOW_BRUSH));
// draw your ellipses here
You can only create dotted or dashed pens with widths of 1 or 0. You used 2, so the command failed.
Also, you should select the pen back out of the DC before you delete it.

Related

Win32 - Change background color under ENTIRE 'Static' control area?

VS2019 c++
This is how I'm declaring a 'Static' label in my humble Win32 application:
hLabel = CreateWindowW(L"Static", L"My Application Text", WS_VISIBLE | WS_CHILD | ES_MULTILINE | ES_AUTOVSCROLL | ES_AUTOHSCROLL, 20, 50, 700, 50, hWnd, NULL, NULL, NULL);
Each line of text uses about 25 pixel worth vertically. So I effectively have room for two lines worth of text in this control since it is declared as 50 pixels high.
I would like to override the default colors used to paint the control, so I experiment with this code:
case WM_CTLCOLORSTATIC:
{
HDC hEdit = (HDC)wParam;
SetTextColor(hEdit, RGB(0, 255, 0));
SetBkColor(hEdit, RGB(0, 0, 255));
return 0;
}
This works "great" except it does not paint the entire area of the control?
As you can see above, the Text color is applied to the characters and the 'Background' color is applied not to the entire area of the control, enclosed by the WS_BORDER, but only to the extent of the characters. I start by filling the control with 100 characters. That's why you only see "one" line of text. My question is "how should I go about filling the entire are of the control"? Which is declared as having an area of 700 pixel wide by 50 pixel high.
I confess I searched around quite a bit but I feel I'm going in circle.
The answer is "42" -- kidding!
This is how I changed my code :
case WM_CTLCOLOREDIT:
{
HDC hEdit = (HDC)wParam;
SetTextColor(hEdit, RGB(0, 0, 255));
SetBkColor(hEdit, RGB(255, 255, 0));
SetBkMode(hEdit, TRANSPARENT);
BackEDIT = CreateSolidBrush(RGB(255, 255, 0));
return (INT_PTR)BackEDIT;
}
And then I added :
case WM_DESTROY:
DeleteObject(BackEDIT);
PostQuitMessage(0);
return 0;
So, adding a BRUSH and deleting the BRUSH. Works perfect!

C++ Win32 API - CreateFont(): the documentation example is confusing

The Win32 API function CreateFont() documentation has a confusing example:
As you can see below, they made 3 calls to CreateFont() using the same HANDLE (hFont).. and at the end they have called DeleteObject() for the last one only... but before EndPaint() (while the font is being select to the DC).
I've found this example so misleading about the way DeleteObject() must be used.
I hope if someone could confirm or justify this code.
The example:
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);
//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);
//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;
}

win32 drawing function plot with brush

I'm supposed to write an application using win32 API which draws a function f(x)= x^2 plot. To accomplish this I'm asked to use HBRUSH structure, but there seems to be no appropriate procedure in win32 API. There are tons of them mostly used to draw complete shapes.
Is there one I can use to draw my plot point by point?
Brush is intended to draw surfaces, rect areas, filling, etc; you really need pens
Try this:
HDC hdc = /* init this */;
HPEN pen = CreatePen(PS_SOLID, 0, RGB(0, 0, 0));
HGDIOBJ old_pen = SelectObject(hdc, pen);
// move to first poing in plot
MoveToEx(hdc, startingpoint_x, statingpoint_y, NULL);
// executes for each point in plot
LineTo(hdc, pointx, pointy);
// clean up
SelectObject(hdc, old_pen);
DeleteObject(pen);

Win32 can't get SetBkMode Transparency to work

I am writing a simple program, that prints some text on the screen, overlaying the other windows.
#include "stdafx.h"
#include <Windows.h>
int _tmain(int argc, _TCHAR* argv[])
{
HWND hwnd = GetDesktopWindow();
HDC hdc;
RECT rect;
//LPRECT rect = new RECT;
wchar_t text[] = L"test";
GetClientRect(hwnd, &rect);
do{
hdc = GetWindowDC(hwnd);
SetBkMode(hdc, TRANSPARENT);
SetTextColor(hdc, RGB(100, 100, 100));
DrawText(hdc, text, -1, &rect, DT_NOCLIP);
ReleaseDC(hwnd, hdc);
Sleep(15);
} while (1);
return 0;
}
The problem is that I would like the background of the printed text to be transparent, but SetBkMode does not seem to work (it actually makes no difference if I set it to OPAQUE or TRANSPARENT) so I get a solid background. Any ideas? What am I missing?
edit: Changed LPRECT to RECT, as suggested.
edit: using transparent window:
creating window:
CreateWindowEx(WS_EX_TOPMOST | WS_EX_LAYERED, // extended style
(LPCWSTR)WINDOW_CLASS_NAME, // class
L"test", // title
NULL,
0, 0, // initial x,y
400, 300, // initial width, height
NULL, // handle to parent
NULL, // handle to menu
hinstance,// instance of this application
NULL)
globals:
wchar_t tst_Str[] = L"TEST";
WM_PAINT:
PAINTSTRUCT ps;
HDC hdc;
RECT rc;
hdc = BeginPaint(hwnd, &ps);
GetClientRect(hwnd, &rc);
SetTextColor(hdc, RGB(255, 0, 0));
DrawText(hdc, tst_Str, -1, &rc,NULL);
EndPaint(hwnd, &ps);
return 0;
Windows are responsible for painting themselves. The system is not designed to allow external parties to draw on other windows in the manner you are attempting. You will have to recalibrate your expectations.
If you wish to draw something you should create a window and draw on it. You are at liberty to make the window a transparent layered window and position your drawing so that it appears on top of another window. And you also gain the benefit that you don't need to run a busy loop. You can paint in the standard way, in response to WM_PAINT messages.
To make a layered window appear on the desktop, you have to call SetLayeredWindowAttributes function, for example
SetLayeredWindowAttributes(hWnd,
RGB(255, 255, 255), // The transparent color
128, // Opacity of the window
LWA_ALPHA | LWA_COLORKEY); // Enable both features
This example will make portions of the window with white color completely transparent. Parameter bAlpha specifies the opacity of the window (the pixels not affected with crKey).
Here's a screen shot of such window with Test text floating over browser window with this question:
If you create your window without border, using these window styles: WS_POPUP | WS_SYSMENU, then it will look like on the screen shot. I included WS_SYSMENU to have the standard window menu in the taskbar. To force the taskbar to display a button for popup window, include WS_EX_APPWINDOW extended style.

Bitblt blackness

I am running this following code,
HDC hdc;
HDC hdcMem;
HBITMAP bitmap;
RECT c;
GetClientRect(viewHandle, &c);
// instead of BeginPaint use GetDC or GetWindowDC
hdc = GetDC(viewHandle);
hdcMem = CreateCompatibleDC(hdc);
// always create the bitmap for the memdc from the window dc
bitmap = CreateCompatibleBitmap(hdc,c.right-c.left,200);
SelectObject(hdcMem, bitmap);
// only execute the code up to this point one time
// that is, you only need to create the back buffer once
// you can reuse it over and over again after that
// draw on hdcMem
// for example ...
Rectangle(hdcMem, 126, 0, 624, 400);
// when finished drawing blit the hdcMem to the hdc
BitBlt(hdc, 0, 0, c.right-c.left,200, hdcMem, 0, 0, SRCCOPY);
// note, height is not spelled i before e
// Clean up - only need to do this one time as well
DeleteDC(hdcMem);
DeleteObject(bitmap);
ReleaseDC(viewHandle, hdc);
The code is just fine. But I am seeing black color around this rectangle. Why is that? Here is an example image.
The bitmap is most likely initialized to be all black. You are then drawing a white rectangle that between x-coordinates 126 and 624. Hence, everything to the left of x=126 and to the right of x=624 stays black.
Edit: The documentation for CreateCompatibleBitmap doesn't state how the bitmap will be initialized, so you should explicitly initialize the bitmap with a specific colour, as Goz suggests, using FillRect:
RECT rc;
rc.left=0;
rc.top=0;
rc.right=c.right-c.left;
rc.bottom=200;
FillRect(hdcMem, &rc, (HBRUSH)GetStockObject(GRAY_BRUSH));
This example fills the bitmap in gray -- you may need to CreateSolidBrush your own brush if you need a different colour. (Don't forget to call DeleteObject when you're done.)
As a side note, I find it a bit strange that your bitmap is being set to a constant height of 200 -- the normal thing would be to make the height of the bitmap equal to the height of the window (as is done for the width).
Might it be because you haven't initialised the memory bitmap area to a given colour? Try FillRect'ing the background to a different colour then draw your white rectangle over it and see what happens.
Per MSDN http://msdn.microsoft.com/en-us/library/dd162898.aspx:
The rectangle is outlined by using the current pen and filled by using the current brush.
Consider calling FillRect instead, or select an appropriate pen prior to calling Rectangle'.
I used:
// Fill the background
hdcMem->FillSolidRect(c, hdcMem->GetBkColor());
Just as a note.

Resources