Me again guys, I've managed to learn up till now about most basics regarding window creation and message system, now I wanted to ask about formatting because I didn't manage to find anything about my particular case on google.
Here is what it looks like so far:
The boxes with 0s in them are Static windows since I didn't really get the Rect paint job. I also need it to be dynamic; the boxes will display an element from an int array that I'll transfer over to a wchar_t array for output.
Now is it possible to change the font, lets say increase it and make it bold? Or is it only possible using print text function?
Any help would be much appreciated since I'm really trying to make this "centered" so to speak.
EDIT:
Another question just so I don't make another post:
I just noticed that my stupid static windows don't update after I change the values in array I'm printing in them and repaint them. E.g. each zero is contained in wchar_t array[16][15]; and after I print this setup and change lets say array[13][0] = 'A'; nothing happens, is it due to Static window type or is it because of me being noobish and using MoveWindow to repaint them XD?
The windows message WM_SETFONT will do it. First there should be a font created, and then it is used in the parameter for WM_SETFONT.
When the font and window have been created, use
SendMessage(wnd, WM_SETFONT, (WPARAM)font, FALSE);
to set the default font for the window.
If you want to use a default windows font, you can create one like this:
HFONT font = NULL;
NONCLIENTMETRICS ncm;
memset(&ncm, 0, sizeof(NONCLIENTMETRICS));
ncm.cbSize = sizeof(NONCLIENTMETRICS);
if(SystemParametersInfo(SPI_GETNONCLIENTMETRICS,
sizeof(NONCLIENTMETRICS), &ncm, 0)) {
font = CreateFontIndirect(&ncm.lfMessageFont);
}
There are other default fonts in NONCLIENTMETRICS that you could use.
Of course you can also create a font from a typeface name and other information, but there is no guarantee that there is such a font on different systems.
HFONT CreateFont(
int nHeight, // height of font
int nWidth, // average character width
int nEscapement, // angle of escapement
int nOrientation, // base-line orientation angle
int fnWeight, // font weight
DWORD fdwItalic, // italic attribute option
DWORD fdwUnderline, // underline attribute option
DWORD fdwStrikeOut, // strikeout attribute option
DWORD fdwCharSet, // character set identifier
DWORD fdwOutputPrecision, // output precision
DWORD fdwClipPrecision, // clipping precision
DWORD fdwQuality, // output quality
DWORD fdwPitchAndFamily, // pitch and family
LPCTSTR lpszFace // typeface name
);
Related
I am using Microsoft Windows (32 bit). Please, no Visual Studio anything, or .net.
I have the following that works if I have a windows handle to use for it:
// I have a handle to a window.
// HWND Handle_Of_SomeWindow
// I previously assigned a handle for that and use it.
// I have some Unicode text that I am using.
wstring SomeWideStringText = L"C++ stole my lunch money.";
// I convert that wstring to LPWSTR using
LPWSTR Text_Being_Added = const_cast<wchar_t*>(SomeWideStringText.c_str());
//I create a rectangle to use in my DrawTextExW
RECT rc;
// If I have a handle to a window then I can do this.
GetClientRect(Handle_Of_SomeWindow, & rc);
//But, if I do not have a handle to a window and if I only have a hdc, then that does not work.
When I have an HDC without a window handle (I think that this is a memory dc but I do not yet understand that so well) which I am using in double buffering, then there is no handle to use. And, I can not get a handle for it. Get handle from DC does not work.
So, my question is How do I get a rectangle or &rc for that to use in my command of :
DrawTextExW(HDC_of_FRONT_BUFFER_001, Text_Being_Added, -1, & rc, DT_WORDBREAK, nullptr);
?
Maybe there might be something else other than a rectangle &rc that I could use, but I have not found it.
I have been studying this and I do not understand how to get a rectangle or a &rc to use.
You're misunderstanding what the rectangle you provide to DrawTextEx is, it's not the size of your bitmap, it's the size you want your text to occupy. It should obviously be less than or equal to the size of your backing bitmap, but it has no other relation to it.
then there is no handle to use. And, I can not get a handle for it. Get handle from DC does not work.
Literally no idea what you're trying to express here.
I do not understand how to get a rectangle or a &rc to use
Again, you aren't handed this, you provide it.
A memory DC has a bitmap selected into it, and that bitmap has a size. In most cases your code created that bitmap, so it should already know the size.
But if it doesn't, you have a couple options.
Option 1: You can select the bitmap out of the DC, get its size, and then select it back in. This is kind of kludgy and I've omitted error checking:
// assuming you're given hdcMem...
HBITMAP hbmpTemp = CreateCompatibleDC(hdcMem, 1, 1);
HBITMAP hbmpActual = SelectObject(hdcMem, hdcTemp);
BITMAP bm = {0};
GetObject(hbmpActual, sizeof(bm), &bm);
// now your size is in bm.bmWidth and bm.bmHeight,
RECT rc = {0, 0, bm.bmWidth, bm.bmHeight};
SelectObject(hdcMem, hdcActual); // put the memory DC back
DeleteObject(hbmpTemp);
Option 2: [untested] You could try to query the DC for its "resolution" caps. I know this works for device DCs, like a monitor or printer. I don't know whether it works for a memory DC.
int width = GetDeviceCaps(hdcMem, HORZRES);
int height = GetDeviceCaps(hdcMem, VERTRES);
I have an application, and I imported some fonts into the resource.
Now, I want to use those resourced fonts inside the application, without installing them to the computer that runs it.
The way I want to use the font resources is that I want to set a label's font to the resourced font by sending WM_SETFONT message to it.
Generally, if the font is already installed on the computer I would use the following code:
HDC hdc = GetDC(hwnd);
//here hwnd is the handle to the window.
const TCHAR* fontName = TEXT("/* THE FONT NAME */");
//this is where I'd enter the font name, but it only works when the font is already installed on the computer.
const long nFontSize = NFONTSIZE(7);
//this is where I set the font size.
LOGFONT logFont = {0};
logFont.lfHeight = -MulDiv(nFontSize, GetDeviceCaps(hdc, LOGPIXELSY), 72);
logFont.lfWeight = FW_SEMIBOLD;
_tcscpy_s(logFont.lfFaceName, fontName);
HFONT font = CreateFontIndirect(&logFont); //get the font handle
as soon as I get the HFONT handle, it's no difficulty to send the WM_SETFONT message to the label with:
SendMessage(hwnd, WM_SETFONT, (WPARAM)font, static_cast<LPARAM>(MAKELONG(TRUE, 0)));
//here hwnd is the handle of the static label.
But now, I don't want to set the font by this way because this only works when the specified font is already installed on the computer. I have MY OWN font file with the .ttf format imported as resource. I want to set the label's font to THIS .ttf font.
Assuming you have a token IDF_MYFONT defined for the resource ID, then you can embed your font in the executable with a line like this in your .rc (or .rc2) script:
IDF_MYFONT BINARY "..\\MyFont.ttf" // Or whatever the path to your font file is.
You can load and lock the font resource using code like the following:
HANDLE hMyFont = INVALID_HANDLE_VALUE; // Here, we will (hopefully) get our font handle
HINSTANCE hInstance = ::GetModuleHandle(nullptr); // Or could even be a DLL's HINSTANCE
HRSRC hFntRes = FindResource(hInstance, MAKEINTRESOURCE(IDF_MYFONT), L"BINARY");
if (hFntRes) { // If we have found the resource ...
HGLOBAL hFntMem = LoadResource(hInstance, hFntRes); // Load it
if (hFntMem != nullptr) {
void* FntData = LockResource(hFntMem); // Lock it into accessible memory
DWORD nFonts = 0, len = SizeofResource(hInstance, ares);
hMyFont = AddFontMemResourceEx(FntData, len, nullptr, &nFonts); // Fake install font!
}
}
Then, when you've finished with the font, you can release it from memory like this:
RemoveFontMemResourceEx(hMyFont);
I've included some checks on the return values for the system calls, but you can add others. And you will need to be able to handle the cases where any of these fail (e.g. providing a default font).
While the font is loaded/locked in memory, you can use it as though it were installed on the system: for example, using its name in a LOGFONT structure:
LOGFONT MyLogFont = { -8, 0, 0, 0, 400, FALSE, FALSE, FALSE, ANSI_CHARSET,
OUT_TT_PRECIS, CLIP_DEFAULT_PRECIS, CLEARTYPE_QUALITY,
VARIABLE_PITCH | FF_SWISS, L"MyFontName" };
Feel free to ask for further clarification and/or explanation.
Funny thing, I was just dealing with this problem yesterday night...
To solve it, the values passed into FindResourceW must match the resource type:
const auto resourceHandle{ FindResourceW(nullptr, MAKEINTRESOURCE(IDR_FONT1), RT_FONT) };
const auto resourceLoad{ LoadResource(nullptr, resourceHandle) };
const auto pResource{ LockResource(resourceLoad) };
//do something with the resource pointer here...
FreeResource(resourceLoad);
This should give you a pointer to the resource, and you can then extract the font by creating a new file and write to it using WriteFile. To get the size of the resource, use SizeofResource.
Or you can create the font by passing in the resource pointer into AddFontMemResourceEx.
I have written a runtime-created dialog class that doesn't use any resource files based on this example: http://blogs.msdn.com/b/oldnewthing/archive/2005/04/29/412577.aspx
It is compiled on a Windows 7 x64 machine, but as an x86 application. The dialog is part of a larger program that at other places use normal dialogs with resource files (MFC).
The dialog is launched by DialogBoxIndirectParam like this:
DialogBoxIndirectParam(NULL, m_template.GetTemplate(), NULL, DlgProc, reinterpret_cast<LPARAM>(this));
The dialog shows fine on all Windows 7 x64 machines I have tried, but it doesn't work on Windows XP x86 machines. I don't know if it's the Windows version or the CPU bit part that is the culprit.
Some interesting but strange things:
Dialogs in the same program using normal resources work fine in both Win 7 and Win XP.
When comparing the runtime-created dialog template byte by byte I can see no difference from the resource-constructed dialogs.
As long as I don't add any controls what so ever to the dialog, it WILL display in XP, but if I add as much as a single static it won't.
I have monitored the callback function and when it starts it sends WM_SETFONT, WM_DESTROY, WM_NCDESTROY and then dies. It's like it gives up somewhere between WM_SETFONT and WM_CREATE.
I have found others with similar problems but none exactly like mine: http://social.msdn.microsoft.com/Forums/zh/vcgeneral/thread/45989a10-2785-486d-94ae-4f1f3e1ca651, http://cboard.cprogramming.com/windows-programming/39218-createdialog-failure.html
I must say that I'm at my wits end about this, I'm just not good enough at win32 programming to figure out exactly what could be wrong here.
Here is what the template code looks like:
DialogTemplate::DialogTemplate(const std::wstring& title, WORD width, WORD height) :
m_numControls(0)
{
AddHeader(title, width, height);
AddFont();
}
DialogTemplate::~DialogTemplate(void)
{
}
void DialogTemplate::AddHeader(const std::wstring& title, WORD width, WORD height)
{
// Write out the extended dialog template header
m_data.Write<WORD>(1); // dialog version
m_data.Write<WORD>(0xFFFF); // extended dialog template
m_data.Write<DWORD>(0); // help ID
m_data.Write<DWORD>(0); // extended style
m_data.Write<DWORD>(WS_CAPTION | WS_SYSMENU | DS_SETFONT | DS_MODALFRAME);
m_data.Write<WORD>(0); // number of controls (placeholder)
m_data.Write<WORD>(32); // X
m_data.Write<WORD>(32); // Y
m_data.Write<WORD>(width); // width
m_data.Write<WORD>(height); // height
m_data.WriteString(L""); // no menu
m_data.WriteString(L""); // default dialog class
m_data.WriteString(title.c_str()); // title
}
bool DialogTemplate::AddFont()
{
// Write out font
HDC hdc = GetDC(NULL);
if (!hdc)
return false;
NONCLIENTMETRICSW ncm = { sizeof(ncm) };
if (!SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, 0, &ncm, 0))
return false;
if (ncm.lfMessageFont.lfHeight < 0)
ncm.lfMessageFont.lfHeight = -MulDiv(ncm.lfMessageFont.lfHeight, 72, GetDeviceCaps(hdc, LOGPIXELSY));
m_data.Write<WORD>((WORD)ncm.lfMessageFont.lfHeight); // point
m_data.Write<WORD>((WORD)ncm.lfMessageFont.lfWeight); // weight
m_data.Write<BYTE>(ncm.lfMessageFont.lfItalic); // Italic
m_data.Write<BYTE>(ncm.lfMessageFont.lfCharSet); // CharSet
m_data.WriteString(ncm.lfMessageFont.lfFaceName);
return true;
}
void DialogTemplate::AddControl(LPCWSTR pszType, WORD x, WORD y, WORD width, WORD height, const std::wstring& text, DWORD controlId, DWORD style)
{
m_data.AlignToDword();
m_data.Write<DWORD>(0); // help id
m_data.Write<DWORD>(0); // window extended style
m_data.Write<DWORD>(WS_CHILD | style); // style
m_data.Write<WORD>(x); // x
m_data.Write<WORD>(y); // y
m_data.Write<WORD>(width); // width
m_data.Write<WORD>(height); // height
m_data.Write<DWORD>(controlId); // control ID
m_data.WriteString(pszType); // control type (as string)
m_data.WriteString(text.c_str()); // text
m_data.Write<WORD>(0); // no extra data
++m_numControls;
m_data.Overwrite<WORD>(m_numControls, NUM_CTRL_OFFS);
}
void DialogTemplate::AddControl(DWORD dwType, WORD x, WORD y, WORD width, WORD height, const std::wstring& text, DWORD controlId, DWORD style)
{
m_data.AlignToDword();
m_data.Write<DWORD>(0); // help id
m_data.Write<DWORD>(0); // window extended style
m_data.Write<DWORD>(WS_CHILD | style); // style
m_data.Write<WORD>(x); // x
m_data.Write<WORD>(y); // y
m_data.Write<WORD>(width); // width
m_data.Write<WORD>(height); // height
m_data.Write<DWORD>(controlId); // control ID
m_data.Write<DWORD>(dwType); // control type (as DWORD)
m_data.WriteString(text.c_str()); // text
m_data.Write<WORD>(0); // no extra data
++m_numControls;
m_data.Overwrite<WORD>(m_numControls, NUM_CTRL_OFFS);
}
Wow, it's super annoying to paste code here if it's indented by tabs :-/
The code looks about right, but it does not show the produced template, which fails to instantiate.
One thing I noticed weird is:
m_data.Write<DWORD>(dwType); // control type (as DWORD)
This does not sound about right, you need 0xFFFF in front if it:
If the first element is 0xFFFF, the array has one additional element
that specifies the ordinal value of a predefined system class. The
ordinal can be one of the following atom values.
Under Win32 I believe the dialog template strcture needs to be byte aligned.
I want to create an irregularily shaped/skinned window (just with rounded, alpha blended corners for now). Upon creating the top-level window i am processing the WM_CREATE message and do the following:
Create a compatible memory DC
Create a DIB section compatible with the window DC
Select DIB into memory DC
Do the drawing of my backdrop
Apply alpha channel and premultiply RGB values
Call UpdateLayeredWindow()
Later on I am planning on rounding of the edges by setting the alpha channel and premultiplying the bits in question to make that happen.
Now, if I create for instance a button in my window, it will not render itself. I know why, and I am trying to come up with an elegant solution to making my custom controls (child windows) here.
My initial approach was to ditch using child windows in the first place and just let the top level window do all the drawing and also input handling, hit testing, and so on. I found this to be way to tedious and instead I want to let Windows handle all this for me.
Now, I know if I create a child window, it of course behaves normally (e.g. reacting to user input), and I want to leverage this. I am planning on creating the child windows (custom controls) normally using CreateWindowEx() so they get a window handle, and recieve window messages without me having to worry about passing them manually.
Somehow I need to get these windows painted, and as I see it, the only possible way to do this is from the routine that paints the whole top level window. I need to invent some kind of logic to get the top level window's paint routine to paint my child windows whenever necessary. As far as I understand the UpdateLayeredWindow() function need to redraw the whole window.
Is it sensible to for instance have the child controls render an image of themselves that are sent to the top level window's paint routine? Like for instance the child window sending a user WM to the top level window passing pointer to its rendered bitmap as a WPARAM and pointer to a structure defining its position and size as a LPARAM.
Any better ideas? Does this make any sense at all?
Thanks,
Eirik
I was trying to do a very similar thing.
From reading this and other searching web. It seams the recommended mechanism for drawing a CWnd (or HWND) and it's children onto your own CDC (or HDC) is to use the printing API.
CWnd has methods Print and PrintClient and which send WM_PRINT correctly. There is also the Win32 methods: PrintWindow.
I had trouble getting this to work at first but I eventually got the right method and parameters. The code that worked for me was:
void Vg2pImageHeaderRibbon::Update() {
// Get dimensions
CRect window_rect;
GetWindowRect(&window_rect);
// Make mem DC + mem bitmap
CDC* screen_dc = GetDC(); // Get DC for the hwnd
CDC dc;
dc.CreateCompatibleDC(screen_dc);
CBitmap dc_buffer;
dc_buffer.CreateCompatibleBitmap(screen_dc, window_rect.Width(), window_rect.Height());
auto hBmpOld = dc.SelectObject(dc_buffer);
// Create a buffer for manipulating the raw bitmap pixels (per-pixel alpha).
// Used by ClearBackgroundAndPrepForPerPixelTransparency and CorrectPerPixelAlpha.
BITMAP raw_bitmap;
dc_buffer.GetBitmap(&raw_bitmap);
int bytes = raw_bitmap.bmWidthBytes * raw_bitmap.bmHeight;
std::unique_ptr<char> bits(new char[bytes]);
// Clears the background black (I want semi-transparent black background).
ClearBackgroundAndPrepForPerPixelTransparency(dc, raw_bitmap, bytes, bits.get(), dc_buffer);
// To get the window and it's children to draw using print command
Print(&dc, PRF_CLIENT | PRF_CHILDREN | PRF_OWNED);
CorrectPerPixelAlpha(dc, raw_bitmap, bytes, bits.get(), dc_buffer);
// Call UpdateLayeredWindow
BLENDFUNCTION blend = {0};
blend.BlendOp = AC_SRC_OVER;
blend.SourceConstantAlpha = 255;
blend.AlphaFormat = AC_SRC_ALPHA;
CPoint ptSrc;
UpdateLayeredWindow(
screen_dc,
&window_rect.TopLeft(),
&window_rect.Size(),
&dc,
&ptSrc,
0,
&blend,
ULW_ALPHA
);
SelectObject(dc, hBmpOld);
DeleteObject(dc_buffer);
ReleaseDC(screen_dc);
}
This worked for me just as is. But incase you window or children don't support WM_PRINT I looked at how it was implemented for CView class I discovered that this class provides a virtual method called OnDraw(CDC* dc) that is provided with a DC to draw with. WM_PAINT is implemented something like this:
CPaintDC dc(this);
OnDraw(&dc);
And the WM_PAINT is implemented:
CDC* dc = CDC::FromHandle((HDC)wParam);
OnDraw(dc);
So the WM_PAINT and WM_PRINT results an OnDraw(), and the drawing code implemented once.
You can basically add this same logic your own CWnd derived class. This may not be possible using visual studio's class wizards. I had to add the following to message map block:
BEGIN_MESSAGE_MAP(MyButton, CButton)
...other messages
ON_MESSAGE(WM_PRINT, OnPrint)
END_MESSAGE_MAP()
And my handler:
LRESULT MyButton::OnPrint(WPARAM wParam, LPARAM lParam) {
CDC* dc = CDC::FromHandle((HDC)wParam);
OnDraw(dc);
return 0;
}
NOTE: If you add a custom WM_PRINT handler on a class that already supports this automatically then you loose the default implementation. There isn't a CWnd method for OnPrint so you have to use the Default() method to invoke the default handler.
I have't tried the following but I expect it works:
LRESULT MyCWnd::OnPrint(WPARAM wParam, LPARAM lParam) {
CDC* dc = CDC::FromHandle((HDC)wParam);
// Do my own drawing using custom drawing
OnDraw(dc);
// And get the default handler to draw children
return Default();
}
Above I defined some strange methods: ClearBackgroundAndPrepForPerPixelTransparency and CorrectPerPixelAlpha. These allow me to set the background of my dialog be semi-transparent when having the child controls be full opaque (this is my per-pixel transparency).
// This method is not very efficient but the CBitmap class doens't
// give me a choice I have to copy all the pixel data out, process it and set it back again.
// For performance I recommend using another bitmap class
//
// This method makes every pixel have an opacity of 255 (fully opaque).
void Vg2pImageHeaderRibbon::ClearBackgroundAndPrepForPerPixelTransparency(
CDC& dc, const BITMAP& raw_bitmap, int bytes, char* bits, CBitmap& dc_buffer
) {
CRect rect;
GetClientRect(&rect);
dc.FillSolidRect(0, 0, rect.Width(), rect.Height(), RGB(0,0,0));
dc_buffer.GetBitmapBits(bytes, bits);
UINT* pixels = reinterpret_cast<UINT*>(bits);
for (int c = 0; c < raw_bitmap.bmWidth * raw_bitmap.bmHeight; c++ ){
pixels[c] |= 0xff000000;
}
dc_buffer.SetBitmapBits(bytes, bits);
}
// This method is not very efficient but the CBitmap class doens't
// give me a choice I have to copy all the pixel data out, process it and set it back again.
// For performance I recommend using another bitmap class
//
// This method modifies the opacity value because we know GDI drawing always sets
// the opacity to 0 we find all pixels that have been drawn on since we called
// For performance I recommend using another bitmap class such as the IcfMfcRasterImage
// ClearBackgroundAndPrepForPerPixelTransparency. Anything that has been drawn on will get an
// opacity of 255 and all untouched pixels will get an opacity of 100.
void Vg2pImageHeaderRibbon::CorrectPerPixelAlpha(
CDC& dc, const BITMAP& raw_bitmap, int bytes, char* bits, CBitmap& dc_buffer
) {
const unsigned char AlphaForBackground = 100; // (0 - 255)
const int AlphaForBackgroundWord = AlphaForBackground << 24;
dc_buffer.GetBitmapBits(bytes, bits);
UINT* pixels = reinterpret_cast<UINT*>(bits);
for (int c = 0; c < raw_bitmap.bmWidth * raw_bitmap.bmHeight; c++ ){
if ((pixels[c] & 0xff000000) == 0) {
pixels[c] |= 0xff000000;
} else {
pixels[c] = (pixels[c] & 0x00ffffff) | AlphaForBackgroundWord;
}
}
dc_buffer.SetBitmapBits(bytes, bits);
}
Here is a screen shot of my test application. When the user hovers the mouse over the "more buttons" button the dialog box is created with a semi-transparent background. The buttons "B1" to "B16" are child controls derived from CButton and are being drawn using the Print() call show above. You can see the semi-transparent background at the right hand edge of the view and between the buttons.
I think I'm going to go for this solution:
Top level window
The top level window maintains two bitmaps. One which is the displayed window and one without any of the child controls rendered. The latter one will only need redrawing when the window changes size. The window will have a message handler that renders a child control on the displayed bitmap. The message handler will expect a pointer to either a DIB containing the child control, or to the actual bits (not sure which is best at the moment), as the WPARAM, and a pointer to a structure containing the rectangle that the child shall be drawn into as the LPARAM. A call to BitBlt() will be made to clear out the underlying surface (this is where the other bitmap comes in) prior to an AlphaBlend() call for rendering the child control bitmap onto the displayed bitmap surface.
The parent window will call the EnumChildWindows whenever it is resized or for some reason need to redraw its children. There could of course be some kind of invalidation regime enforced here to reduce unnecessary rendering of the child controls. Not sure if the speed increase is worth the effort, though.
Child windows
Upon creation of the child control instance, an internal bitmap compatible with that of the top-level window is created. The child renders itself into this internal bitmap and whenever it needs redrawing it notifies its parent window via the SendMessage() function, passing a pointer to its bitmap as the WPARAM, and a RECT as the LPARAM defining its position and dimensions. If the parent needs redrawing, it issues a message down to all its child windows requesting their bitmap. Childs will then respond with the same message that they normally would send when they decide they need redrawing themselves.
Eirik
To quote the MSDN page for WM_PAINT:
The WM_PAINT message is generated by the system and should not be sent by an application. To force a window to draw into a specific device context, use the WM_PRINT or WM_PRINTCLIENT message. Note that this requires the target window to support the WM_PRINTCLIENT message. Most common controls support the WM_PRINTCLIENT message.
So it looks like you can iterate through all the child windows with EnumChildWindows and send them WM_PRINT with your memory DC between steps 5 and 6.
It will look something like this:
static BOOL CALLBACK MyPaintCallback(HWND hChild,LPARAM lParam) {
SendMessage(hChild,WM_PRINT,(WPARAM)lParam,(LPARAM)(PRF_CHECKVISIBLE|PRF_CHILDREN|PRF_CLIENT));
return TRUE;
}
void MyPaintMethod(HWND hWnd) {
//steps 1-5
EnumChildWindows(hWnd,MyPaintCallback,MyMemoryDC);
//step 6
}
(unmanaged C++)
I already succeeded drawing PNG files to a transparent layered window that I can drag around the desktop, but now my problem is drawing text on a transparent layered window
Here's my code and my attempt at drawing text in the middle, it's important to note that i'm using the screenDC instead of using the one in WM_PAINT messages
[edit]
updated code after the comments, now i'm just trying to write text on the bitmap before getting the HBITMAP version which i need to use
this time I'm using DrawString because textout() isn't GDI+, I hope DrawString really is GDI+ lol
still doesn't work though, wonder what i'm doing wrong
void Draw() // draws a frame on the layered window AND moves it based on x and y
{
HDC screenDC( NULL ); // grab screen
HDC sourceDC( CreateCompatibleDC(screenDC) );
POINT pos = {x,y}; // drawing location
POINT sourcePos = {0,0}; // top left of image
SIZE size = {100,100}; // 100x100 image
BLENDFUNCTION blendFunction = {0};
HBITMAP bufferBitmap = {0};
Bitmap* TheBitmap = crnimage; // crnimage was already loaded earlier
// ------------important part goes here, my attempt at drawing text ------------//
Gdiplus::Graphics Gx(TheBitmap);
// Font* myFont = new Font(sourceDC);
Font myFont(L"Arial", 16);
RectF therect;
therect.Height = 20;
therect.Width = 180;
therect.X = 0;
therect.Y = 0;
StringFormat format;
format.SetAlignment(StringAlignmentCenter);
format.GenericDefault();
Gdiplus::SolidBrush GxTextBrush(Gdiplus::Color(255, 255, 0,255));
WCHAR thetext[] = L"Sample Text";
int stats = Gx.DrawString(thetext, -1, &myFont, therect, &format, &GxTextBrush);
if(stats) // DrawString returns nonzero if there is an error
msgbox(stats);
stats = Gx.DrawRectangle(&Pen(Color::Red, 3), therect);
// the rectangle and text both draw fine now
// ------------important part goes here, my attempt at drawing text ------------//
TheBitmap->GetHBITMAP(0, &bufferBitmap);
HBITMAP oldBmpSelInDC;
oldBmpSelInDC = (HBITMAP)SelectObject(sourceDC, bufferBitmap);
// some alpha blending
blendFunction.BlendOp = AC_SRC_OVER;
blendFunction.SourceConstantAlpha = wndalpha;
blendFunction.AlphaFormat = AC_SRC_ALPHA;
COLORREF colorKey( RGB(255,0,255) );
DWORD flags( ULW_ALPHA);
UpdateLayeredWindow(hWnd, screenDC, &pos, & size, sourceDC, &sourcePos,
colorKey, &blendFunction, flags);
// release buffered image from memory
SelectObject(sourceDC, oldBmpSelInDC);
DeleteDC(sourceDC);
DeleteObject(bufferBitmap);
// finally release the screen
ReleaseDC(0, screenDC);
}
I've been trying to write text on my layered window for two days now, but from those attempts I know there are several ways I can go about doing this
(unfortunately I have no idea how exactly)
The usual option I see is drawing text on a bitmap, then rendering the bitmap itself
Use Gdi+ to load a bitmap
Create a Graphics object from the bitmap
Use DrawString to write text to the bitmap
Dispose of the Graphics object
Use the bitmap Save method to save the result to a file
Apparently one can also make a graphics object from a DC, then draw text on the DC, but again i have no clue as to how to do this
The overall approach looks right, but I think you've got some problems with the DrawString call. Check out the documentation (especially the sample) on MSDN.
Gx.DrawString(thetext, 4, NULL, therect, NULL, NULL)
The third, fifth, and sixth parameters (font, format, and brush) probably need to be specified. The documentation doesn't say that they are optional. Passing NULL for these is probably causing GDI+ to treat the call as a no-op.
The second parameter should not include the terminating L'\0' in the string. It's probably safest to use -1 if your string is always terminated.