I have created a dialog in MFC and used CDateTimeCtrl to show/set the time. Till Windows 10 Build 10240 it was showing proper time but once you take latest updates of Windows, CDateTimeCtrl displays blank values.
The font used is "MS Shell Dlg".
My question is why CDateTimeCtrl shows blank value on Windows 10 RS2 (Build 1703), even though time is set. Is font "MS Shell Dlg" not supported on Windows 10 or is there any other reason?
Following is the code:
SYSTEMTIME systime;
long lStyle;
CFont Fontvar;
CDateTimeCtrl m_DateTimeCtrl
GetLocalTime(&systime);
lStyle = ::GetWindowLong(m_DateTimeCtrl.m_hWnd, GWL_STYLE);
lStyle |= DTS_TIMEFORMAT;
::SetWindowLong(m_DateTimeCtrl.m_hWnd, GWL_STYLE, lStyle);
Fontvar.CreatePointFont(10, _T("MS Shell Dlg"));
m_DateTimeCtrl.SetFont(&Fontvar);
m_DateTimeCtrl.SetFormat(_T("HH:mm:ss"));
m_DateTimeCtrl.SetTime(&systime);
Ah I saw this at CodeProject and as it may be as I suspected now seeing the code.
CFont Fontvar; must remain valid >>> for the lifetime <<< of CDateTimeCtrl m_DateTimeCtrl it isn't clear from the code that is true.
CFont Fontvar; is valid when you create m_DateTimeCtrl but we don't know if that code is just in some function and thus CFont Fontvar; is on the local stack and about to disappear.
It is also your responsibility to delete that font.
Update: Ok I take it back they have indeed broken MFC. You can't use setfont on the CDateTimeCtrl with any font not just that one. The only solution is go around MFC and use the windows API directly.
LOGFONT lf;
// clear out structure
memset(&lf, 0, sizeof(LOGFONT));
// request a 12-pixel-height font
lf.lfHeight = 12;
// request a face name "MS Shell Dlg"
_tcsncpy_s(lf.lfFaceName, LF_FACESIZE, _T("MS Shell Dlg"), _tcslen(_T("MS Shell Dlg")));
// create the font
HFONT hfont = ::CreateFontIndirect(&lf);
// Send the WM_SETFONT message to the date time control
m_dateTimeCtrl.SendMessage(WM_SETFONT, (WPARAM)hfont, 1);
Related
I noticed that in a (Delphi 10.3.3 32-bit VCL app on Windows 10 64-bit) application that the caption of a label would not display if the string was "really" long. Further testing indicates that it is not restricted to a TLabel. TStaticText also behaves the same way and probably all of the TGraphicControls.
With a TLabel on a form, testing indicates that it will show the caption if it is 43,679 characters in length. But any longer and the caption disappears. No combination of autosize, wordwrap, EllipsisPosition changed this behaviour. Tracing through the delphi code, it comes down to 2 statments in VCL.Controls:
Perform(WM_SETTEXT, 0, Buffer);
Perform(CM_TEXTCHANGED, 0, 0);
Buffer holds the correct value of the caption's string in all cases. But at 43,680 chars the caption disappears. So it appears to be a Windows limit but I cannot find any confirmation of this.
I wrote a simple resource display program, that displays in a very small window some stats, like amount of free RAM. I want it to be visible on any desktop when I switch between them, how to achieve that?
UPDATE:
Thanks to n.m. I am on the right track (hopefully), here is what I have got so far:
unsigned int ints[2];
ints[0] = 0xFFFFFFFF;
ints[1] = 2;
XChangeProperty(d, w, XInternAtom(d, "_NET_WM_DESKTOP", 1),
XA_ATOM,
32,
PropModeReplace,
(unsigned char*)ints,
2);
It compiles, but it does not do anything, i.e. the window is still only visible on the desktop it was originally started. What's wrong with my code?
X11 or Xlib by themselves have no notion of desktops or switching between desktops. It's all in your window manager. Usually a window informs the WM about it needs through window properties.
Modern Freedesktop-compliant window managers use _NET_WM_DESKTOP property. Set it to 0xFFFFFFFD before mapping the window.
Edit the correct incantation is
unsigned long prop = 0xFFFFFFFF; // note long! even if long is 64 bit
XChangeProperty(d, w, XInternAtom(d, "_NET_WM_DESKTOP", 1),
XA_CARDINAL, // note CARDINAL not ATOM
32,
PropModeReplace,
(unsigned char*)&prop,
1); // note 1
XMapWindow(d, w); // map after changing the property
You can use the xprop command line utility to verify that the property is set correctly.
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.
The picture below (enlarged, so you better see the differences) shows Font differences between dynamically created Edit controls (the upper two examples) and Edit Controls created from the Dialog Editor (the lower example). How can I make the font of my dynamically created CEdit controls looking like the default (the lower example)?
I have created the CEdit Controls like following:
obj->CreateEx(WS_EX_CLIENTEDGE, _T("EDIT"), _T(""),
WS_CHILD | WS_VISIBLE | WS_TABSTOP,
rect.left, rect.top, rect.Width(), rect.Height(),
GetSafeHwnd(), reinterpret_cast<HMENU>(mId));
obj->SetFont(&mFont); // mFont was created in the Dialog Constructor
// with mFont.CreatePointFont(80, _T("MS Shell Dlg"));
Thanks for your help!
The first example is using the System font (SYSTEM_FONT), as retrieved with the GetStockObject function, which is a bitmap font that has not been used since the days of Windows 3. More information is available on Raymond Chen's blog, and Michael Kaplan's blog.
The second example is using the "MS Shell Dlg" font, just like you asked it to. That actually maps to a font called "Microsoft Sans Serif" or "MS Sans Serif", the UI font back in the days of Windows 95 and 98. This is also known as DEFAULT_GUI_FONT, which indeed used to be an accurate name for it, but alas, it is accurate no longer.
Beginning with Windows 2000 (and continued in XP), Tahoma was used as the default UI font. This is what you are seeing in the third example: Tahoma 8 pt. Unfortunately, even on those operating systems, "MS Shell Dlg" does not return Tahoma--it still returns MS Sans Serif, which is why it looks wrong.
So, you could simply specify Tahoma as the GUI font, but that wouldn't really be correct, because it would break in older versions of the OS where Tahoma isn't installed or supported, or on foreign language versions of the operating system, where a different font is used out of necessity. Instead, you're supposed to specify the DS_SHELLFONT flag, which Raymond talks about here.
And all was fine and good until Windows Vista came out. And in Windows Vista, the powers that be at Microsoft decided that Tahoma was getting a little long-in-the-tooth and Windows was due for another UI font upgrade. They developed their own special font in-house called Segoe UI, supposedly designed for optimum on-screen readability. And in a special little twist, they decided that the default size should now be 9 pt, instead of 8 pt as used by every previous version of the OS, regardless of the font face. And you would probably think that either "MS Shell Dlg", "MS Shell Dlg2", or DS_SHELLFONT (or all three) would get you this new-fangled Segoe UI font, but you'd be wrong.
Uh oh. Now things get tricky... Not only does Vista use a different font than XP that is not easily accessible with a one-size-fits-all identifier, but it also uses a different size, changing the way your dialog will look on those systems, if you can get it to display at all. In many, many places, the Windows shell team appeared to simply punt the challenge--Tahoma 8 pt is used all over the place, even with the Aero theme enabled, when it's supposed to be using Segoe UI 9 pt. This kind of thing really makes the UI look unpolished, and it was the subject of lots of nitpicking back in the early days of Vista. Now, it seems most people have forgotten about it, but the UI hasn't started looking any less scattered and inconsistent.
And you're not the Windows shell team: you can't get away with this in your own app. The Top Rules for the Windows Vista User Experience even state explicitly that you should always:
Use Segoe UI, the new Windows Vista system font.
Respect the user's settings by always referencing the system font, sizes, and colors using the Windows Theme APIs. Don't use fixed values for fonts, sizes, or colors.
To be honest, I haven't really heard a good solution to this problem yet. And I suspect that by the time I ever do, no one will need to support Windows XP anymore (although most people aren't quite there yet). But here's what I do: I extract the default system font at runtime using the SystemParametersInfo function. Fortunately, the system message box font (lfMessageFont) is the correct font face and size, regardless of the current version of Windows and the user's chosen theme.
My code to initialize windows or dialogs generally looks something like this (SystemInfo::IsVistaOrLater is a helper function I've written; the implementation is the obvious):
// Get the system message box font
NONCLIENTMETRICS ncm;
ncm.cbSize = sizeof(ncm);
// If we're compiling with the Vista SDK or later, the NONCLIENTMETRICS struct
// will be the wrong size for previous versions, so we need to adjust it.
#if(_MSC_VER >= 1500 && WINVER >= 0x0600)
if (!SystemInfo::IsVistaOrLater())
{
// In versions of Windows prior to Vista, the iPaddedBorderWidth member
// is not present, so we need to subtract its size from cbSize.
ncm.cbSize -= sizeof(ncm.iPaddedBorderWidth);
}
#endif
SystemParametersInfo(SPI_GETNONCLIENTMETRICS, ncm.cbSize, &ncm, 0);
HFONT hDlgFont = CreateFontIndirect(&(ncm.lfMessageFont));
// Set the dialog to use the system message box font
SetFont(m_DlgFont, TRUE);
SendMessage(hWnd, WM_SETFONT, (WPARAM)hDlgFont, MAKELPARAM(FALSE, 0));
Or even easier in MFC, with the handy SendMessageToDescendants method
(m_DlgFont is a CFont object defined for the class):
// Get the system message box font
NONCLIENTMETRICS ncm;
ncm.cbSize = sizeof(ncm);
SystemParametersInfo(SPI_GETNONCLIENTMETRICS, ncm.cbSize, &ncm, 0);
LOGFONT lfDlgFont = ncm.lfMessageFont;
m_DlgFont.CreateFontIndirect(&lfDlgFont);
// Set the dialog and all its controls to use the system message box font
SetFont(m_DlgFont, TRUE);
SendMessageToDescendants(WM_SETFONT, (WPARAM)m_DlgFont.m_hFont, MAKELPARAM(FALSE, 0), TRUE);
If you're not using MFC, I highly recommend implementing your own recursive version of SendMessageToDescendants. It makes the initialization code a lot simpler.
In my projects i copy the font from the main dialog. But the main dialog must be built by the Dialog Editor.
#include <windowsx.h> // for Get/SetWindowFont()
SetWindowFont(editHwnd, GetWindowFont(mainDlgHwnd), true);
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.