SendMessage and ncm not changing font - c++

I have looked for answers and I have found some that didn't work, so I would be grateful if anybody can help with this.
From this post I used the NONCLIENTMETRICS typedef and the SendMessage function to find and create a font.
I have ran it before everything in the WM_CREATE switch, though the post said to run it before the window is created, and I'm pretty sure WM_CREATE is run after the window is created but I tried it anyway.
Code of the setfont() function:
void setfont(HWND hWnd) {
NONCLIENTMETRICS ncm;
ncm.cbSize = sizeof(NONCLIENTMETRICS);
SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &ncm, 0);
HFONT hFont = CreateFontIndirect(&ncm.lfMessageFont);
SendMessage(hWnd, WM_SETFONT, (WPARAM)hFont, MAKELPARAM(TRUE, 0));
}
Please tell me if I need to show any other code.
I have tried the CreateFont way, but that didn't work as well, so I'm hoping someone can tell me where I went skewer.
Note I'm using Visual Studio 2022
Thanks in advance.

Found the answer via this post
Steps:
Make the font, Via CreateFont or CreateFontIndirect
Add a HWND to the button or static control your trying to make
Last of all, use this line to set the font:
SendMessage([HWND of the control], WM_SETFONT, (WPARAM)[Font HFONT], TRUE);

Related

WS_EX_TOOLWINDOW tool windows doesn't work as expected

In our legacy code Windows extended style WS_EX_TOOLWINDOW is being used.This is basically for showing the title bar narrow.But recently in the later winodws versions the title bar is not drawn as narrow.That is WS_EX_TOOLWINDOW doesnt give a narrow title bar in the newer windows versions.Making the title bar narrow is done on a click event.Let me know if there is another way of achieving this?
I have read that we need to handle WM_NCCALCSIZE.But is there any other way of doing it?.Or if this is the only way,how can I handle it in a button click?
Code Snippet:
HWND hwnd = m_hWnd;
......
DWORD dwStylesEx = ::GetWindowLong( hwnd, GWL_EXSTYLE );
if ( bNarrowTitle == true)
{
dwStylesEx |= WS_EX_TOOLWINDOW;
}
else
{
dwStylesEx &= ~WS_EX_TOOLWINDOW;
}
...
::SetWindowLong( hwnd, GWL_EXSTYLE, dwStylesEx );
MSDN says:
Certain window data is cached, so changes you make using SetWindowLong will not take effect until you call the SetWindowPos function. Specifically, if you change any of the frame styles, you must call SetWindowPos with the SWP_FRAMECHANGED flag for the cache to be updated properly.
The default look just doesn't distinguish it in any way. Which suggests that you will just have to live with it.
It's probably been changed due to not being finger friendly if smaller!
Refer : WS_EX_TOOLWINDOW doesn't give look I want
As you said, handle WM_NCCALCSIZE may be the only way to handle the size of non-client areas.
Refer: How to set the size of the Non-client area of a Win32 window (native)

win32 - Using the default button font in a button

I'm creating a small WinAPI application in C++. I am trying to create a button on my form by using the code:
HWND hwndButton = CreateWindow(
TEXT("BUTTON"),
TEXT("Click Here"),
WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON, // Styles
10,
10,
100,
30,
hwnd,
NULL,
(HINSTANCE)GetWindowLong(hwnd, GWL_HINSTANCE),
NULL);
This code is based off of an MSDN sample. My issue is that it uses a bold font on the button like this:
When I want to use the standard font like this:
I already have the preprocessor directive at the top of my file to enable visual styles.
#pragma comment(linker,"\"/manifestdependency:type='win32' \
name='Microsoft.Windows.Common-Controls' version='6.0.0.0' \
processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
What steps should I take to use the standard system wide font?
Thanks
GetStockObject isn't the recommended way of retrieving the GUI font (it doesn't take themes into account, and different fonts can be chosen for buttons, menus, etc). Instead you should use SystemParametersInfo (see Remarks section of GetStockObject).
It is not recommended that you employ this method to obtain the current font used by dialogs and windows. Instead, use the SystemParametersInfo function with the SPI_GETNONCLIENTMETRICS parameter to retrieve the current font. SystemParametersInfo will take into account the current theme and provides font information for captions, menus, and message dialogs.
NONCLIENTMETRICS metrics = {};
metrics.cbSize = sizeof(metrics);
SystemParametersInfo(SPI_GETNONCLIENTMETRICS, metrics.cbSize, &metrics, 0);
HFONT guiFont = CreateFontIndirect(&metrics.lfCaptionFont);
// When you're done with the font, don't forget to call
DeleteObject(guiFont);
There's no such thing as default system wide font for controls, initially you get a control created with "System" font, that's what you see on first picture. When button is created as part of a dialog, it uses a font from dialog template, so using something like "MS Shell Dlg" with appropriate size + WM_SETFONT on a button should give you the same result as on picture 2. Note that there's no physical MS Shell Dlg font on a system, it's mapped to particular font according to registry settings.
Common control manifest has nothing to do with this, behavior has not changed with comctl32 version 6.
The default GUI font is stored in DEFAULT_GUI_FONT, and can be retrieved via
GetStockObject(DEFAULT_GUI_FONT);
To set the font of the button you can use:
HWND yourButton; // use CreateWindow or anything else to get this
SendMessage(yourButton, WM_SETFONT, (LPARAM)GetStockObject(DEFAULT_GUI_FONT), true);
A convenient way of doing this without calling SendMessage on every single child window manually is to use the EnumChildWindows function with the following callback function -
Create the callback function EnumChildProc:
BOOL CALLBACK EnumChildProc(
HWND hWnd,
LPARAM lParam
)
{
HFONT hfDefault = *(HFONT *) lParam;
SendMessageW(hWnd, WM_SETFONT, (WPARAM) hfDefault, MAKELPARAM(TRUE, 0));
return TRUE;
}
At the start of your (w)WinMain function, add the code:
NONCLIENTMETRICSW ncm;
HFONT hfDefault;
ZeroMemory(&ncm, sizeof(NONCLIENTMETRICSW));
ncm.cbSize = sizeof(NONCLIENTMETRICSW);
SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &ncm, FALSE);
hfDefault = CreateFontIndirectW(&ncm.lfMessageFont);
Then, after the ShowWindow call, add this line:
EnumChildWindows(hWnd, EnumChildProc, (LPARAM)&hfDefault);

C++ Add A Bitmap from resource to Picture Control

i want to display a bitmap on my Picture control,
but actually no matter what Im trying, it doesnt work.
Right now my method looks like this:
SendDlgItemMessage(hWnd ,picture_CTRL, BM_SETIMAGE , IMAGE_BITMAP, (LPARAM) MAKEINTRESOURCE(IDB_BITMAP1));
I have also already tried to use the
STM_SETIMAGE
Message, but it wont work as well.
My Picture Control property "Type" is set to "Bitmap" and my Bitmap has an ID in resource.h
Hope you guys can help :)
First, you can't just mix and match messages in standard Windows controls. BM_SETIMAGE and STM_SETIMAGE have completely different values. If you are using a Static control, use STM_SETIMAGE. If you are using a Button control, use BM_SETIMAGE.
Second, the documentation for STM_SETIMAGE says that the LPARAM must be a handle to the image. You are passing a resource ID. You need to get the handle by calling LoadImage first. For example:
HBITMAP hBitmap = reinterpret_cast<HBITMAP>(LoadImage(
GetModuleHandle(NULL),
MAKEINTRESOURCE(IDB_BITMAP1),
IMAGE_BITMAP,
0,
0,
0));
SendDlgItemMessage(
hWnd,
picture_CTRL,
STM_SETIMAGE,
IMAGE_BITMAP,
reinterpret_cast<LPARAM>(hBitmap));
Note that according to the documentation you are responsible for deleting the bitmap when you are done with it.
EDITS: Note that I had two problems in my original version of the code, both caused by copying and pasting from the question. I failed to pass the handle as the LPARAM myself and I used BM_SETIMAGE instead of STM_SETIMAGE. I will also add a note in the answer that, as Cody Gray pointed out, the MSDN documentation for a function or message will tell you whether you can use MAKEINTRESOURCE.

Flickering using WM_DRAWITEM

It seems like I can't get pass this issue with owner-draw controls. I've super-classed a status control. I am trying to customize but still retain the same functionality. Basically, I want to change the background and text. I'm using Direct2d (or ID2D1DCRenderTarget interface) for the drawing. I have successful changed the background by using WM_NCPAINT; although, you can use WM_ERASEBKGRND if you want. However, both methods acted as a control in my experiment and flickering still occurred. Moreover, flickering doesn't occur when the WPARAM of SB_SETTEXT is NOT SET to SBT_OWNERDRAW. Therefore, I came to a conclusion that WM_DRAWITEM is the culprit. Is there anyway I can fix this flickering issue with owner-draw statusbar?
You can avoid flickering if you turn on double buffering for you control.
Set the WS_EX_COMPOSITED extended style:
http://msdn.microsoft.com/en-us/library/windows/desktop/ff700543(v=vs.85).aspx
e.g. when handling WM_CREATE, call (WTL or MFC):
ModifyStyleEx(0, WS_EX_COMPOSITED);
Well, seems like I figured it out. When super-classing a status-bar follow these sets to avoid flickering.
**Note: This has only been tested with visual styles turned off. SetWindowTheme(hWndStatus, L"", L"");
Also, the parent window must have WS_CLIPCHILDREN set in the style parameter during window creation.
1: Override WM_SIZE. Make a call to InvalidateRect(m_hWnd, NULL, TRUE) and return 0 unless you want the default sizing; in this case, call CallWindowProc.
2: Override WM_ERASEBKGND and return -1.
3: Override WM_NCPAINT and place your drawing code here.
Handling WM_NCPAINT. People seem to have trouble understanding how to handle WM_NCPAINT. Here is how I do it.
if (wParam == 1) {
hdc = GetWindowDC(m_hWnd);
} else {
hdc = GetDCEx(m_hWnd, (HRGN) wParam, DCX_WINDOW | DCX_INTERSECTRGN | DCX_CACHE);
}
Then do drawing with the DC.
4: In the parent procedure (WndProc or whatever) call SetWindowPos(..., SWP_DRAWFRAME) with the handle to the statusbar. This will resize your statusbar.
5: Send a message via SendMessage(hWndStatusbar, SB_SETPARTS, 1, (LPARAM) &parts);
6: Send a message via SendMessage(hWndStatusbar, SB_SETTEXT, LOBYTE(0) | SBT_OWNERDRAW, L"Ready"). Sample code for WM_DRAWITEM:
...
WM_DRAWITEM:
LPDRAWITEMSTRUCT lpDIS = (LPDRAWITEMSTRUCT) lParam;
m_pFramework->m_pD2D1RenderTarget->BindDC(lpDIS->hDC, &lpDIS->rcItem);
m_pFramework->m_pD2D1RenderTarget->BeginDraw();
m_pFramework->m_pD2D1RenderTarget->Clear(D2D1::ColorF(D2D1::ColorF::CadetBlue));
D2D1_RECT_F rf = D2D1::RectF(
PixeltoDipX(lpDIS->rcItem.left),
PixeltoDipY(lpDIS->rcItem.top),
PixeltoDipX(lpDIS->rcItem.right),
PixeltoDipY(lpDIS->rcItem.bottom)
);
m_pFramework->m_pD2D1RenderTarget->DrawText(
(LPCWSTR) lpDIS->itemData,
wcslen((WCHAR*) lpDIS->itemData) + 1,
m_pFramework->m_pTextFormat,
rf,
m_d2dCaptionTextColor
);
m_pFramework->m_pD2D1RenderTarget->EndDraw();
break;
....
This should stop flickering. Also, do not call InvalidateRect(hWndStatus, NULL, TRUE) in the parent's WM_SIZE. This was the main reason it flickered.

Why SelectObject is called twice?

I read code in MFC, but was confused with the code below:
void EditView::ResetDefaultFont()
{
HFONT hFont = (HFONT)::GetStockObject(DEFAULT_GUI_FONT);
CDC* pDC = GetDC();
CFont* pFont = pDC->SelectObject(CFont::FromHandle(hFont));
pDC->SelectObject(pFont);
::DeleteObject(hFont);
}
Why CDC Select the default font first(CFont* pFont = pDC->SelectObject(CFont::FromHandle(hFont));), but select pFont again?
The first SelectObject call changes the font selected in the device context.
The second SelectObject call resets the font to whatever it was before the first call.
While that answers the "why" for the second call, which is what you ask about, I do not have any idea what the point of doing the complete call sequence is. I find no documentation results for ResetDefaultFont, neither online in MSDN Library nor in the local Visual Studio 2012 help. Just to be thorough I created a new default MFC project in VS 2012, and used the identifier ResetDefaultFont in the constructor of a class derived from CEditView. It did not compile: no such.
So,
where did you get that ResetDefaultFont function from?
The answer is quite simple.
This code is just for getting the current font of the DC.
If they had placed the code following these statements, it would have been obvious.