I'm writing an application for a Pocket PC 2003 device. In it there is a dialog where various text information is shown. The information is separated so that each piece resides inside its own label, defined as LTEXT in the resource file.
Now my problem is that, at the moment, all text lables have the same font and style (normal or simple, i.e. not bold or italic); I want want one to be set in bold. I know that I can set the font to bold in the resource file, but that sets the style of all labels.
How does one achieve this? I've seen it be used in the Windows 'About' screen so I know it's possible. I've written the program in C++ using the Win32 API directly (except for certain dialogs where I've used the resource file) so I would appreciate if the answer was given in the same language and approach.
Thanks.
In the resource editor, edit the static text item, and change its control ID to something unique: IDC_BOLD for example.
In the DialogProc for the dialog boxes that is hosting the control, add a WM_CTLCOLORSTATIC handler:
case WM_CTLCOLORSTATIC:
HDC hdc;
HWND hwndCtl;
hwndCtl = (HWND) lParam;
hdc = (HDC) wParam;
if( GetWindowLong(hwndClt, GWL_ID ) == IDC_BOLD )
{
SetBkMode(hdc,TRANSPARENT);
SetTextColor(hdc,RGB(0xff,0,0)); // turn the text red for fun :)
SelectObject(hdc,hBoldFont); // but you want this...
return (INT_PTR)GetSysColorBrush(COLOR_BTNFACE);
//return 0L; // if visual themes are enabled (common controls 6) then 0 is better.
}
// default processing
return 0;
You are developing for Pocket PC 2003, I don't know what buttons styles are available. This Page refers of course to desktop XP. But, if the buttons in the dialogs are not flat grey 95esq buttons, then it might be more appropriate to return 0 as that will paint the text background correctly if the dialogs background is not plain grey.
Pre-visual styles a return of 0 causes the system to reset the DC so its important to know which return is appropriate.
Related
I want to create a window with the following properties:
Thick border ("double border" as described in MSDN)
Not resizable
Icon in the title
Close button in the title
It sounds so simple and we can find this kind of windows everywhere in Windows. But as soon as I disable ability to resize my window I also lose the thick border. Here is the illustration of my problem:
The height of my test window's caption bar is slightly less than that of a Shell property dialog, but I would like it to be the same height.
I have tried to use WinSpy and copy all styles from Explorer's window to mine, but this did not help.
I don't know what's going on under the hood, but I found two solutions:
Switch to the newer Platform Toolset (which means drop support of Windows XP)
Disable resizing by writing custom WM_NCHITTEST handler
The second option is quite simple and I do not want drop Windows XP support for a silly reason. Job is done:
LRESULT CListEditorDlg::OnNcHitTest(CPoint point)
{
LRESULT retVal = CDialog::OnNcHitTest(point);
switch (retVal)
{
case HTBOTTOM:
case HTBOTTOMLEFT:
case HTBOTTOMRIGHT:
case HTLEFT:
case HTRIGHT:
case HTTOP:
case HTTOPLEFT:
case HTTOPRIGHT:
retVal = HTBORDER;
}
return retVal;
}
My question arises from our program running on a Japanese OS. One of my co-workers had done something like embed a property sheet on a dialog and the property sheet has multiple pages. Everything works fine on other languages except Japanese.
On Japanese systems, some of the controls get cut off because there is not enough space. I determined that this was because on Japanese systems, the font used by the property sheet and hence the property pages was different than the font used by the parent dialog of the property sheet. For the record, the font used by the parent dialog and all the property pages was MS Shell Dlg, 8:
FONT 8, "MS Shell Dlg", 0, 0, 0x1
I wanted a simple fix to try and ameliorate the problem for Japanese and all potential system. I examined the fonts on Japanese Windows 7 property sheets/pages and they always SEEMED to be the Default GUI Font. So, when I was creating my first dialog, on the fly after loading the DIALOGTEMPLATE into memory with the MFC class CDialogTemplate, I would modify the font of the parent dialog to match the default GUI font, and everything would be fine on Japanese Windows--Window 7, that is.
A customer has now found that this is not a valid solution for Windows 8/8.1--it exhibits the original problem. After examining the fonts on a Windows 8.1 VM, I did determine that the property sheet on Windows 8.1 and the child property pages does not use the Default GUI Font.
That's lots of words to ask. is there a way to determine what the default font used by property sheets on a Windows system?
I figure my ugly workaround would be to create a property sheet with one property page, determine the font used by that property sheet and page, and then modify the dialog template of my parent dialog on the fly to use that font. Since property sheets have some quirks about activation (they get activated on creation even if invisible), I'd rather not, but it seems to be my only choice--besides re-engineering of my co-worker's dialogs.
Yes, apparently the font for Property Sheet and Wizard is different. There is a dialog template for each language. In WinAPI PropertySheet uses the font from that template.
To find this font use the following (I only tested this on Windows 10)
#define IDD_PROPSHEET 1006
#define IDD_WIZARD 1020
HMODULE hmod = LoadLibrary(L"comctl32.dll");
if (hmod)
{
HRSRC hres = FindResource(hmod, MAKEINTRESOURCEW(IDD_PROPSHEET), (LPWSTR)RT_DIALOG);
if (hres)
{
HGLOBAL hglob = LoadResource(hmod, hres);
if (hglob)
{
CString fontname;
WORD fontsize;
CDialogTemplate::GetFont((DLGTEMPLATE*)hglob, fontname, fontsize);
TRACE(L"%s %d\n", fontname, fontsize);
}
}
FreeLibrary(hmod);
}
This might be somewhat outdated. The font obtained from SystemParametersInfo(SPI_GETNONCLIENTMETRICS...) must already be compatible because it's the main display font.
For some reason, MFC takes things further and applies that template font to property pages as well. MFC does other things which I can't understand, for example VS2015 has this code in "dlgprop.cpp"
LANGID langid = GetUserDefaultUILanguage();
if ((PRIMARYLANGID(langid) == LANG_JAPANESE) && IsFontInstalled(_T("MS UI Gothic")))
{
WORD wLang = MAKELANGID(LANG_JAPANESE, 0x3f);
if (wLang != 0)
{
hResource = ::FindResourceExW(hInst, (LPWSTR) RT_DIALOG,
MAKEINTRESOURCEW(bWizard ? IDD_WIZARD : IDD_PROPSHEET), wLang);
}
...
}
I don't know why it forces a sub-language if a certain font is present. Also as #PRinCEKtd points out, this font might be outdated (but the font could be still be installed) You can step through CPropertySheet to find all the font manipulations.
see also codeguru link, Custom Font in Property Sheets
try use
NONCLIENTMETRICS ncm = { GetNONCLIENTMETRICSWSize() };
if (SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0)){..}
usual all system controls (status bar, list view, tree view,menu, message box..) use fonts from this struct
where GetNONCLIENTMETRICSWSize() can be like this (on XP/2003 (major < 6) struct size is less on 4 byte compare vista+)
ULONG GetNONCLIENTMETRICSWSize()
{
static ULONG m;
if (!m)
{
RtlGetNtVersionNumbers(&m, 0, 0);
}
return m < 6 ? sizeof(NONCLIENTMETRICS) - 4 : sizeof(NONCLIENTMETRICS);
}
From Windows Vista onwards, the Meiryo font family was used as default in the Windows user interface to support Japanese. I think before vista, it was MS Gothic...
How about manually setting a default windows font directly? There are many fonts that support Japanese as well as a wide variety of languages. Some of them have been present from XP upto 10, though they might have some updates.
I have an non read only edit control for which I need to change colors so I handle WM_CTLCOLOREDIT. It works well when I am typing continuously but the problem is when I hit backspace or delete or even start typing from the middle of an existing text, the display is all junked up. That remains untill I cause a repaint by resizing the parent etc. How to fix this?
Edit: Some detail. The problem seems only when the background color is set and not when just the text color is set. The code looks like this
ON_MESSAGE(WM_CTLCOLOREDIT, OnEditColor)
LRESULT CMyWindow::OnEditColor(WPARAM wp, LPARAM lp)
{
HDC hdc = (HDC)wp;
HWND hwnd = (HWND)lp;
if(hwnd == m_edit.GetSafeHwnd())
{
// SetBkMode(hdc, TRANSPARENT);
MyControlInfo*pcti;// accessed from somewhere
SetTextColor(hdc, pcti->theme.clrText);
// return (LRESULT)pcti->brush.GetSafeHandle();
}
return 0;
}
Thanks
I rather doubt that this is caused by this code. It is the kind of problem you get when you try to subclass the edit control and override painting. Windows version 2 having to run on a 386SUX and 20 years of appcompat prevented Microsoft from fixing this control so it only draws itself in the WM_PAINT message handler. It indeed draws directly to the screen when you backspace. There's no workaround for it.
Same comment applies as in your previous question, use a real edit control.
You should set a background color with SetBkColor (And don't use SetBkMode) and return a valid brush. (You don't know how the control does its painting, it is free to use ExtTextOut with ETO_OPAQUE etc)
http://msdn.microsoft.com/en-us/library/bb761691(v=vs.85).aspx
Return Value
If an application processes this
message, it must return the handle of
a brush. The system uses the brush to
paint the background of the edit
control.
So try something like:
return static_cast<LRESULT>(::GetSysColorBrush(COLOR_WINDOW));
When creating a control (e.g. an edit control) on the fly using CreateWindow, it usually starts out with an ugly (boldish sans serif) font.
Usually I wok around that by grabbing the parent dialog's font, and setting it to the control - I can't even say if this is a good idea.
How do I "legally" fetch the right font?
The "correct" way to get the font used in dialog boxes like message boxes, etc. would be via the SystemParametersInfo() function:
// C++ example
NONCLIENTMETRICS metrics;
metrics.cbSize = sizeof(NONCLIENTMETRICS);
::SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS),
&metrics, 0);
HFONT font = ::CreateFontIndirect(&metrics.lfMessageFont);
::SendMessage(ctrlHWND, WM_SETFONT, (WPARAM)font, MAKELPARAM(TRUE, 0));
Don't forget to destroy the font when the controls are destroyed:
::DeleteObject(font);
You can look up the MSDN documentation for NONCLIENTMETRICS and SystemParametersInfo() to see what other system-wide parameters you can retrieve.
i need to implement the functionality of EM_SETCUEBANNER, where a text hint appears inside an Edit control:
The catch is that i cannot use version 6 of the Common Controls, which is what is required to get the Microsoft supplied implementation of a cue banner.
i've looked into simply changing the text of the edit control, and the font format to
Dark Gray Italic Text
but it will throw Change events (component wrapper provided by higher component library) that i can't find a way to avoid.
So i was instead going to custom draw the text, drawing the Cue Banner text when the control is unfocused and empty, and rely on default painting otherwise.
The Edit control doesn't nicely expose a custom drawing mechanism, like ListView, TreeView and others provide.
Other people have looked into it, but it seems to be an nearly impossible task:
From the way things are looking, I'll
have to handle the following
messages:
WM_ERASEBKGND, WM_PAINT (for obvious reasons)
WM_SETFOCUS, WM_KILLFOCUS (to prevent
the white bar from displaying --
described above)
WM_CHAR (to process and update the
text in the control)
And I also need to find a way to
display the caret in the control,
since I haven't found a way to allow
Windows to do that for me without also
painting the white bar I mentioned.
This is going to be fun. :rolleyes:
Given that the Windows Edit control was never meant to be custom drawn: does anyone know how to custom draw a Windows Edit control?
Note: i will also accept answers that solve my problem, rather than answering my question. But anyone else wanting to custom draw an Edit control, coming across this question, would probably like an answer.
Custom drawing an Edit control is essentially impossible. There are a few specialized cases were you are doing so little that can get away with it, but you risk breaking badly in the next revision of windows (or when someone runs your app on an older version, or via terminal services, etc).
Just taking over WM_PAINT and WM_ERASEBKGROUND aren't good enough, because the control will sometimes paint on other messages as well.
You are better off just writing your own edit control. I know that's a huge amount of work, but in the long run it will be less work than trying to hack your way into taking over all of the Edit controls' drawing code.
I remember back in the good old days when everyone use to subclass the button control to add color and graphics, etc. The thing is, one day I sat down and just wrote my own button window class. and it was LESS CODE than what we had in our source tree to subclass and custom draw the Windows button.
Create a window class of your own that looks like and empty edit control, that draws the cue text and shows a caret and has focus. Create the edit control also, but position it behind your window. (or leave it hidden)
Then when you get the first WM_CHAR message (or WM_KEYDOWN?). You put your window behind the edit conrol, give focus to the edit, and pass the WM_CHAR message on. From then on the edit control will take over.
You can listen to EN_CHANGE notifications from the edit control if you need to go back to showing your cue text when the edit gets empty. But I'd think that it would be fine to go back to the cue text only when the edit looses focus AND is empty.
Subclassing the EDIT control worked well for me - needed to display some formatting information to the user when editing object attributes (and some attributes could be multiple lines). The important thing, like Adrian said in his answer too, is to call the EDIT control's procedure before your own drawing. Calling it afterward or issuing your own BeginPaint/EndPaint (with return 0 or DefWindowProc) caused issues for me from the text not displaying at all, to it displaying only when resizing but not after editing, to leaving screen litter of the leftover caret. With that, I haven't had any issues regardless of the EDIT control's other repaint times.
Some setup:
SetWindowSubclass(attributeValuesEdit, &AttributeValueEditProcedure, 0, reinterpret_cast<DWORD_PTR>(this));
// Not only do multiline edit controls fail to display the cue banner text,
// but they also ignore the Edit_SetCueBannerText call, meaning we can't
// just call GetCueBannerText in the subclassed function. So store it as
// a window property instead.
SetProp(attributeValuesEdit, L"CueBannerText", L"<attribute value>");
The callback:
LRESULT CALLBACK AttributeValueEditProcedure(
HWND hwnd,
UINT message,
WPARAM wParam,
LPARAM lParam,
UINT_PTR subclassId,
DWORD_PTR data
)
{
...
case WM_PRINTCLIENT:
case WM_PAINT:
{
auto textLength = GetWindowTextLength(hwnd);
if (textLength == 0 && GetFocus() != hwnd)
{
// Get the needed DC with DCX_INTERSECTUPDATE before the EDIT
// control's WM_PAINT handler calls BeginPaint/EndPaint, which
// validates the update rect and would otherwise lead to drawing
// nothing later because the region is empty. Also, grab it from
// the cache so we don't mess with the EDIT's DC.
HDC hdc = (message == WM_PRINTCLIENT)
? reinterpret_cast<HDC>(wParam)
: GetDCEx(hwnd, nullptr, DCX_INTERSECTUPDATE|DCX_CACHE|DCX_CLIPCHILDREN | DCX_CLIPSIBLINGS);
// Call the EDIT control so that the caret is properly handled,
// no caret litter left on the screen after tabbing away.
auto result = DefSubclassProc(hwnd, message, wParam, lParam);
// Get the font and margin so the cue banner text has a
// consistent appearance and placement with existing text.
HFONT font = GetWindowFont(hwnd);
RECT editRect;
Edit_GetRect(hwnd, OUT &editRect);
// Ideally we would call Edit_GetCueBannerText, but since that message
// returns nothing when ES_MULTILINE, use a window property instead.
auto* cueBannerText = reinterpret_cast<wchar_t*>(GetProp(hwnd, L"CueBannerText"));
HFONT previousFont = SelectFont(hdc, font);
SetTextColor(hdc, GetSysColor(COLOR_GRAYTEXT));
SetBkMode(hdc, TRANSPARENT);
DrawText(hdc, cueBannerText, int(wcslen(cueBannerText)), &editRect, DT_TOP|DT_LEFT|DT_NOPREFIX|DT_NOCLIP);
SelectFont(hdc, previousFont);
ReleaseDC(hwnd, hdc);
// Return the EDIT's result (could probably safely just return zero here,
// but seems safer to relay whatever value came from the edit).
return result;
}
}
break;
Writing your own EDIT control (which I've actually done more than once, to partial degrees of completeness compared to the built-in one) is not much work if you do the bare minimum (maybe English only with basic caret support), but it's a LOT of work to get correct if you want caret navigation over complex scripts with variable sized clusters, selection over ranges, IME support, context menus with copy and paste, high contrast modes, and accessibility features such as text to speech. So unlike so many other answers, I recommend not implementing your own EDIT control merely for cue banner text.
Subclass the edit control. Handle WM_PAINT by first calling the original window procedure and then, if it's empty and not in focus, draw the cue text. Pass every other message to the original window procedure.
I've done this--it works. The problem the CodeGuru person had doesn't seem to apply to your situation. I believe he's trying to do more to the appearance. For performance, it looks like the edit control is doing some updates outside of WM_PAINT processing (probably for performance). That's going to make it nearly impossible to take complete control of the appearance. But you CAN draw the cue prompt.
And I also need to find a way to display the caret in the control,
since I haven't found a way to allow Windows to do that for me without
also painting the white bar I mentioned.
If you want to handle WM_PAINT by yourself without forwarding the message to the original windowproc of your superclass, you should not forget to call DefWindowProc. So that the caret will be drawn.
To avoid the white bar you should remove class brush with SetClassLongPtr.
And somehow keep your DC's clipping region to clip Edit controt's ExtTextOut outputs.
The white bar may be the result of OPAQUE option passed to ExtTextOut by Edit control.
Conclusion: Write your own control. No pain, no gain.