Drawing semitransparent child window with image on parent window - winapi

I need to make bird animation in WS_OVERLAPPED window (as shown below). Animation is represented by 8 images:
The blue color in the image (which is RGB(0, 255, 255)) has to be transparent (see screenshot below).
I wanted to do this using CreateWindowEx() (bird would be represented by layered window) with WS_EX_LAYERED argument. Unfortunately bird must be WS_CHILD. Mixing WS_EX_LAYERED | WS_CHILD is not legal in Windows 7:
Windows 8: The WS_EX_LAYERED style is supported for top-level windows and child windows. Previous Windows versions support WS_EX_LAYERED only for top-level windows.
Final effect should look like this (I've already painted window's background - the only problem is the bird):
How can I achieve this effect? How to animate bird in parent window?
If you have any idea how to implement bird animation with transparent background color please share.

Since animation is done even when there's no interaction with the window, we'll need a timer:
case WM_CREATE:
// load resources
SetTimer(hwnd, 0, 250, NULL); // set timer to 250 ms
return 0;
...
case WM_DESTROY:
KillTimer(hwnd, 0);
// release the resources
return 0;
We can invalidate the whole window each timer tick, but it would be better to redraw only needed part. We'll also update the current frame number here:
case WM_TIMER:
frame_number++;
if (frame_number >= 8)
frame_number = 0;
RECT rc = { 30, 30, 80, 80 }; // a rectangle from (30,30) to (80,80)
InvalidateRect(hwnd, &rc, FALSE);
return 0;
Then, we draw the current frame in the WM_PAINT handler:
case WM_PAINT:
// draw the sky
SelectObject(hDCMem, hBird);
TransparentBlt(hDC, 30, 30, 50, 50, hDCMem, frame_number * 51, 0, 50, 50, RGB(0, 255, 255)); // 51 is 50 (side of a bird frame) + 1 (gap between the frames)
// draw the rest
return 0;

I've finally find out how to do it. It's quite tricky.
The full description of the solution is available here - winprog.org/tutorial/transparency.html. For polish readers here is great translation.
Simple idea in brief:
Giving bitmaps the appearance of having transparent sections is quite simple, and involves the use of a black and white Mask image in addition to the colour image that we want to look transparent.
The following conditions need to be met for the effect to work correctly: First off, the colour image must be black in all areas that we want to display as transparent. And second, the mask image must be white in the areas we want transparent, and black elsewhere. The colour and mask images are displayed as the two left most images in the example picture on this page.
Simple solution in brief:
#define TRANSPARENCY_COLOR RGB(0, 255, 255)
birdBmp = (HBITMAP) LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_BITMAP1));
hbmpMask = CreateBitmapMask(birdBmp, TRANSPARENCY_COLOR);
Painting:
case WM_PAINT:
{
hdc = BeginPaint(hWnd, &ps);
HDC birdMaskHdc = CreateCompatibleDC(hdc);
BITMAP bmInfo;
GetObject(birdBmp, sizeof(bmInfo), &bmInfo);
HBITMAP hbmpOld = (HBITMAP) SelectObject(birdMaskHdc, hbmpMask);
BitBlt(hdc, 0, 0, bmInfo.bmWidth, bmInfo.bmHeight, birdMaskHdc, 0, 0, SRCAND);
SelectObject(birdMaskHdc, birdBmp);
BitBlt(hdc, 0, 0, bmInfo.bmWidth, bmInfo.bmHeight, birdMaskHdc, 0, 0, SRCPAINT);
SelectObject(birdMaskHdc, hbmpOld);
DeleteDC(birdMaskHdc);
EndPaint(hWnd, &ps);
break;
}
Cleaning:
case WM_DESTROY:
{
DeleteObject(hbmpMask);
DeleteObject(birdBmp);
PostQuitMessage(0);
break;
}
Function which is responsible for creating bitmap mask:
HBITMAP CreateBitmapMask(HBITMAP hbmColour, COLORREF crTransparent)
{
HDC hdcMem, hdcMem2;
HBITMAP hbmMask, hbmOld, hbmOld2;
BITMAP bm;
GetObject( hbmColour, sizeof( BITMAP ), & bm );
hbmMask = CreateBitmap( bm.bmWidth, bm.bmHeight, 1, 1, NULL );
hdcMem = CreateCompatibleDC( NULL );
hdcMem2 = CreateCompatibleDC( NULL );
hbmOld =( HBITMAP ) SelectObject( hdcMem, hbmColour );
hbmOld2 =( HBITMAP ) SelectObject( hdcMem2, hbmMask );
SetBkColor( hdcMem, crTransparent );
BitBlt( hdcMem2, 0, 0, bm.bmWidth, bm.bmHeight, hdcMem, 0, 0, SRCCOPY );
BitBlt( hdcMem, 0, 0, bm.bmWidth, bm.bmHeight, hdcMem2, 0, 0, SRCINVERT );
SelectObject( hdcMem, hbmOld );
SelectObject( hdcMem2, hbmOld2 );
DeleteDC( hdcMem );
DeleteDC( hdcMem2 );
return hbmMask;
}

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!

Drawing peformance with Win32

I am getting a very poor peformance drawing with Win32. It takes too much time and needs improving. Please advise.
Here is what I do.
HDC dc = GetDC(wnd);
HDC memoryDc = CreateCompatibleDC(dc);
HBITMAP memoryMapBitmap = CreateCompatibleBitmap(dc, 400, 400);
HGDIOBJ originalBitmap = SelectObject(memoryDc, memoryMapBitmap);
Then, I draw in a for-loop as follows.
HBRUSH brush = (HBRUSH)GetStockObject(DC_BRUSH);
SetDCBrushColor(memoryDc, colorRef);
FillRect(memoryDc, &rect, brush);
And finally, I do a cleanup
SelectObject(memoryDc, originalBitmap);
DeleteDC(memoryDc);
ReleaseDC(wnd, dc);
Drawing takes a lot of time (several seconds). Is there a way to draw faster with Win32?
Thanks in advance!
It looks like I have solved it. Below is the solution with some comments.
I have a dialog defined in RC-file. There is a control to display a bitmap image in the dialog.
CONTROL "", IDC_MEMORY_MAP, WC_STATIC, SS_BITMAP | SS_CENTERIMAGE | SS_SUNKEN, 9, 21, 271, 338, WS_EX_LEFT
In the run-time I need to create, draw and display a bitmap:
HWND map = GetDlgItem(dlg, IDC_MEMORY_MAP);
HBITMAP bitmap = createMemoryMapBitmap(map);
bitmap = (HBITMAP)SendMessage(map, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM)bitmap);
DeleteObject(bitmap); // (!) this is a very important line, otherwise old bitmap leaks
Code that finds out the size of the bitmap to create:
HBITMAP createMemoryMapBitmap(HWND map) {
RECT rect = {0, 0, 0, 0};
GetClientRect(map, &rect);
SIZE size = {rect.right - rect.left, rect.bottom - rect.top};
HDC dc = GetDC(map);
HBITMAP bitmap = doCreateMemoryMapBitmap(dc, &size);
ReleaseDC(map, dc);
return bitmap;
}
Finally, we actually create the bitmap and draw on it:
HBITMAP doCreateMemoryMapBitmap(HDC dc, LPSIZE bitmapSize) {
// create 24bpp bitmap in memory in order to draw fast
BITMAPINFO info;
memset(&info, 0, sizeof(info));
info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
info.bmiHeader.biWidth = bitmapSize->cx;
info.bmiHeader.biHeight = bitmapSize->cy;
info.bmiHeader.biPlanes = 1;
info.bmiHeader.biBitCount = 24;
info.bmiHeader.biCompression = BI_RGB;
void *pixels = NULL;
HBITMAP memoryBitmap = CreateDIBSection(dc, &info, DIB_RGB_COLORS, &pixels, NULL, 0);
HDC memoryDc = CreateCompatibleDC(dc); // (!) memoryDc is attached to current thread
HGDIOBJ originalDcBitmap = SelectObject(memoryDc, memoryBitmap);
// drawing code here
// perform windows gdi cleanup
SelectObject(memoryDc, originalDcBitmap); // restore original bitmap in memoryDC (optional step)
DeleteDC(memoryDc); // this releases memoryBitmap from memoryDC
return memoryBitmap;
}
The idea above is to create a 24bpp bitmap in the memory and draw on it. This way drawing is fast, as #IInspectable pointed out.
If display is in the indexed color mode, e.g. 16 or 256 colors, it seems Windows native control is smart enough to convert the color depth automatically displaying the bitmap.

Why would TextOut() be using a different coordinate system than AlphaBlend()?

I'm trying to write a text overlay function that generates a semitransparent background with text on it in the top right hand corner of the viewport. I wrote a test MFC application project with mostly default settings (I don't remember exactly, but AFAIK, none of the settings should cause the problems I'm seeing).
Here is the code:
void DrawSemitransparentRect(CDC& destDC, CRect rect, float percentGrayBackground, COLORREF overlayColour, float overlayPercentOpaque)
{
rect.NormalizeRect();
CDC temp_dc; // Temp dc for semitransparent text background
temp_dc.CreateCompatibleDC(&destDC);
CBitmap layer; // Layer for semitransparent text background
layer.CreateCompatibleBitmap(&destDC, 1, 1);
CBitmap* pOldBitmap = temp_dc.SelectObject(&layer);
BLENDFUNCTION blendFunction = { AC_SRC_OVER, 0, 0, 0 };
auto DrawSemitransparentRectHelper = [&](COLORREF colour, float transparency)
{
temp_dc.SetPixel(0, 0, colour);
blendFunction.SourceConstantAlpha = BYTE(transparency * 255 / 100);
// Draw semitransparent background
VERIFY(destDC.AlphaBlend(rect.left, rect.top, rect.Width(), rect.Height()
, &temp_dc, 0, 0, 1, 1, blendFunction));
};
// Lighten up the area to make more opaque without changing overlay colour.
DrawSemitransparentRectHelper(RGB(255, 255, 255), percentGrayBackground);
// Draw overlay colour
DrawSemitransparentRectHelper(overlayColour, overlayPercentOpaque);
temp_dc.SelectObject(pOldBitmap);
}
void DrawOverlayText(CDC & dc, CFont &windowFont, CRect const& windowRectDP, CString const& overlayText, CRect* pBoundingRectDP)
{
static bool debug = true;
int savedDC = dc.SaveDC();
::SetMapMode(dc.GetSafeHdc(), MM_TWIPS);
// Reset the window and viewport origins to (0, 0).
CPoint windowOrg, viewportOrg;
::SetWindowOrgEx(dc.GetSafeHdc(), 0, 0, &windowOrg);
::SetViewportOrgEx(dc.GetSafeHdc(), 0, 0, &viewportOrg);
LOGFONT logFont;// = { 12 * 10, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 255, _T("Times New Roman") };
windowFont.GetLogFont(&logFont);
logFont.lfHeight = 12 * 10; // 12 point font? Why isn't this *20? TWIPS are 20ths of a point.
// Font for the overlay text
CFont font;
font.CreatePointFontIndirect(&logFont, &dc);
CFont* pOldFont = dc.SelectObject(&font);
// window rect in Logical Points
CRect windowRect(windowRectDP);
dc.DPtoLP(windowRect);
// Get text extent in Logical Points
CRect textRect;
dc.DrawText(overlayText, textRect, DT_CALCRECT);
// inflation rectangle to add pixels around text
CRect inflate(8, 0, 8, 4);
dc.DPtoLP(&inflate);
// Create the bounding rect on the right hand of the view, making it a few pixels wider.
CRect boundingRect(textRect);
if (!debug)
{
boundingRect.InflateRect(inflate);
}
boundingRect.NormalizeRect();
boundingRect += CPoint(windowRect.Width() - boundingRect.Width(), 0);
CRect boundingRectDP(boundingRect);
if (pBoundingRectDP || !debug)
{
// Get the bounding rect in device coordinates
dc.LPtoDP(boundingRectDP);
*pBoundingRectDP = boundingRectDP;
}
if (!debug)
{
// round the bottom corners of the text box by clipping it
CRgn clip;
boundingRectDP.NormalizeRect();
clip.CreateRoundRectRgn(
boundingRectDP.left + 1 // +1 needed to make rounding coner match more closely to bottom right coner
, boundingRectDP.top - boundingRectDP.Height() // Getting rid of top rounded corners
, boundingRectDP.right
, boundingRectDP.bottom + 1
, 16, 16 // rounding corner may have to be more dynamic for different DPI screens
);
::SelectClipRgn(dc.GetSafeHdc(), (HRGN)clip.GetSafeHandle());
clip.DeleteObject();
}
// Calculatte centre position of text
CPoint centrePos(
boundingRect.left + (boundingRect.Width() - textRect.Width()) / 2 + 1
, boundingRect.top + (boundingRect.Height() - textRect.Height()) / 2 + 1);
if (debug)
{
// in debug mode, output text and then put semitransparent bounding rect over it.
dc.SetBkMode(debug ? OPAQUE : TRANSPARENT);
dc.SetBkColor(RGB(255, 0, 0));
dc.SetTextColor(RGB(0, 0, 0));
dc.TextOut(centrePos.x, centrePos.y, overlayText);
DrawSemitransparentRect(dc, boundingRect, 60, RGB(0, .25 * 255, .75 * 255), 40);
}
else
{
// 2 pixel offset in Logical Points
CPoint textShadowOffset(2, 2);
dc.DPtoLP(&textShadowOffset);
// in !debug mode, output semitransparent bounding rect and then put text over it.
DrawSemitransparentRect(dc, boundingRect, 60, RGB(0, .25 * 255, .75 * 255), 40);
dc.SetBkMode(debug ? OPAQUE : TRANSPARENT);
dc.SetTextColor(RGB(0, 0, 0));
dc.TextOut(centrePos.x, centrePos.y, overlayText);
dc.SetTextColor(RGB(255, 255, 255));
dc.TextOut(centrePos.x - textShadowOffset.x, centrePos.y - textShadowOffset.y, overlayText);
}
// Restore DC's state
dc.SelectObject(pOldFont);
dc.RestoreDC(savedDC);
}
// OnPaint() function for CView derived class.
void COverlayOnCViewView::OnPaint()
{
CPaintDC dc(this); // device context for painting
CString m_overlayText = _T("abcdefg ABCDEFG");
CFont windowFont;
LOGFONT logFont = { -12, 0, 0, 0, 400, 0, 0, 0, DEFAULT_CHARSET, 0, 0, CLEARTYPE_QUALITY, 0, _T("Segoe UI") };
windowFont.CreatePointFontIndirect(&logFont, &dc);
CRect windowRect;
GetClientRect(windowRect);
DrawOverlayText(dc, windowFont, windowRect, m_overlayText, nullptr);
}
Now, this works perfectly well in the default project, where I get the following:
But when I put it into another preexisting project, I get this:
You can see that the text is actually positioned above the translucent rectangle.
If I move the rectangle down the height of the text box, by changing
boundingRect += CPoint(windowRect.Width() - boundingRect.Width(), 0);
to
boundingRect += CPoint(windowRect.Width() - boundingRect.Width(), textRect.Height());
I get:
It's like the text function is specifying the bottom left corner rather than the top left corner for placement.
I wrote the free functions so that it should work with any DC, even if that DC has had its coordinate system manipulated, but perhaps I've forgotten to reset something?
The default project is using MFC 14.0.24212.0, but the project I tried to import this code into is using MFC 12.0.21005.1. Could that be an issue? I'm not sure how to change the default project to use the earlier version of MFC to test that.
Edit
Note that in the default project, I could have put the code into the OnDraw() function like this:
void COverlayOnCViewView::OnDraw(CDC* pDC)
{
COverlayOnCViewDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if (!pDoc)
return;
// TODO: add draw code for native data here
CString m_overlayText = _T("abcdefg ABCDEFG");
CFont windowFont;
LOGFONT logFont = { -12, 0, 0, 0, 400, 0, 0, 0, DEFAULT_CHARSET, 0, 0, CLEARTYPE_QUALITY, 0, _T("Segoe UI") };
windowFont.CreatePointFontIndirect(&logFont, pDC);
CRect windowRect;
GetClientRect(windowRect);
DrawOverlayText(*pDC, windowFont, windowRect, m_overlayText, nullptr);
}
The only reason why I didn't was because the application I'm putting this into doesn't have one and I wanted to mimic that project as closely as possible. If you create a default application to test this, remember either to put the ON_WM_PAINT() macro in the MESSAGE MAP or use the OnDraw() function shown instead. They both seem to have the same results in the default project.

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.

win32 - How to draw a rectangle around a text string?

I am new to Win32 and trying to get a GDI based code in C++ ( for technical reasons don't want to use GDI+)
Edit: Simplied the question:
I need to draw a rectangle around the text that is drawn in the middle of the window.
- How can I populate the rectangle co-ordinates?
- Can any one help with the line - Rectangle(x1,y1,x2,y2)? - How to calculate these (x1,y1) & (x2,y2) values?
Thank you..
hdc = BeginPaint(hWnd, &ps);
GetClientRect(hWnd, &rcClient);
SelectObject(hdc, GetStockObject(DEFAULT_GUI_FONT));
SetTextColor(hdc, RGB(255, 0, 0));
DrawText(hdc, wstring(s.begin(),s.end()).c_str(), -1, &rectResult, DT_SINGLELINE | DT_CALCRECT);
DrawText(hdc, wstring(s.begin(),s.end()).c_str(), -1, &rcClient, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
// Here I need help - How to I place the rectangle around the Text - which is drawn in the middle of the window?
// It looks like need to use - rectResult.bottom/top/left/right - but don't know how..
Rectangle(hdc, 0,0,100,100);
You don't actually have to center the text yourself. The GDI text output functions can do that for you if you pass the appropriate flags.
For example, if you call DrawText and pass the DT_CENTER flag, it will automatically draw the text in the middle of the specified rectangle (horizontally centered).
Assuming you have only a single line of text (which it sounds like you do), you can get it to automatically vertically center the text by passing the DT_SINGLELINE and DT_VCENTER flags.
So all you really have to do is write code to divide your window's client area up into 4 equal parts, and then pass those rectangles to the DrawText function. That's not terribly difficult. Put a pencil and paper to it if you can't visualize it in your head.
void PaintWindow(HWND hWnd)
{
// Set up the device context for drawing.
PAINTSTRUCT ps;
HDC hDC = BeginPaint(hWnd, &ps);
HPEN hpenOld = static_cast<HPEN>(SelectObject(hDC, GetStockObject(DC_PEN)));
HBRUSH hbrushOld = static_cast<HBRUSH>(SelectObject(hDC, GetStockObject(NULL_BRUSH)));
// Calculate the dimensions of the 4 equal rectangles.
RECT rcWindow;
GetClientRect(hWnd, &rcWindow);
RECT rc1, rc2, rc3, rc4;
rc1 = rc2 = rc3 = rc4 = rcWindow;
rc1.right -= (rcWindow.right - rcWindow.left) / 2;
rc1.bottom -= (rcWindow.bottom - rcWindow.top) / 2;
rc2.left = rc1.right;
rc2.bottom = rc1.bottom;
rc3.top = rc1.bottom;
rc3.right = rc1.right;
rc4.top = rc1.bottom;
rc4.left = rc1.right;
// Optionally, deflate each of the rectangles by an arbitrary amount so that
// they don't butt up right next to each other and we can distinguish them.
InflateRect(&rc1, -5, -5);
InflateRect(&rc2, -5, -5);
InflateRect(&rc3, -5, -5);
InflateRect(&rc4, -5, -5);
// Draw (differently-colored) borders around these rectangles.
SetDCPenColor(hDC, RGB(255, 0, 0)); // red
Rectangle(hDC, rc1.left, rc1.top, rc1.right, rc1.bottom);
SetDCPenColor(hDC, RGB(0, 255, 0)); // green
Rectangle(hDC, rc2.left, rc2.top, rc2.right, rc2.bottom);
SetDCPenColor(hDC, RGB(0, 0, 255)); // blue
Rectangle(hDC, rc3.left, rc3.top, rc3.right, rc3.bottom);
SetDCPenColor(hDC, RGB(255, 128, 0)); // orange
Rectangle(hDC, rc4.left, rc4.top, rc4.right, rc4.bottom);
// Draw the text into the center of each of the rectangles.
SetBkMode(hDC, TRANSPARENT);
SetBkColor(hDC, RGB(0, 0, 0)); // black
// TODO: Optionally, set a nicer font than the default.
DrawText(hDC, TEXT("Hello World!"), -1, &rc1, DT_CENTER | DT_SINGLELINE | DT_VCENTER);
DrawText(hDC, TEXT("Hello World!"), -1, &rc2, DT_CENTER | DT_SINGLELINE | DT_VCENTER);
DrawText(hDC, TEXT("Hello World!"), -1, &rc3, DT_CENTER | DT_SINGLELINE | DT_VCENTER);
DrawText(hDC, TEXT("Hello World!"), -1, &rc4, DT_CENTER | DT_SINGLELINE | DT_VCENTER);
// Clean up after ourselves.
SelectObject(hDC, hpenOld);
SelectObject(hDC, hbrushOld);
EndPaint(hWnd, &ps);
}
RECT rect={0,0,0,0};
const char *str="Test Text";
DrawText(hDC, str, strlen(str), &rect, DT_CALCRECT | DT_NOCLIP);
Rectangle(hDC,rect.left,rect.top,rect.right,rect.bottom);
DrawText(hDC, str, strlen(str), &rect, DT_CENTER | DT_VCENTER | DT_SINGLELINE|DT_NOCLIP);
Got it finally :) Thanks a lot Cody Gray for pointing me in right direction about this :)
GetTextExtentPoint32(hDC, str, strlen(str), &sz2);
rect2.top=rect2.bottom+sz2.cy;
rect2.right=rect2.top+sz2.cx;
Rectangle(hDC,rect2.left,rect2.top,rect2.right,rect2.bottom);
DrawText(hDC, str, -1, &rect2, DT_CENTER | DT_VCENTER | DT_SINGLELINE|DT_NOCLIP);

Resources