我正在尝试使用 自动调整一些日期时间选择器控件的大小DTM_GETIDEALSIZE
,但我不太了解如何正确使用此消息。如果将返回的宽度视为像素,则返回的宽度似乎很好,但高度似乎不仅相差甚远,而且有时会随着时间而改变!
下面的示例程序创建了三个日期时间选择器。第一个以自定义格式显示日期和时间,第二个仅使用 显示日期DTS_SHORTDATECENTURYFORMAT
,第三个仅使用 显示时间DTS_TIMEFORMAT
。调整窗口大小使用 调整所有三个选择器的大小DTM_GETIDEALSIZE
。宽度似乎很好。但是,前两个的高度始终为 100,而最后一个(时间选择器)的高度似乎从 98 左右开始,每次调整大小都会减少 2,直到达到 16,此时它保持在 16。
这在 Windows Vista 和 Windows 7 上都进行了测试。以下程序中的错误检查不一致(但为了保持这个简单的测试示例,未检查某些错误)。但是,我会注意到 MSDN 明确记录DTM_GETIDEALSIZE
了仅TRUE
在没有指定错误条件的情况下返回。
谢谢。
// 3 june 2015
#define UNICODE
#define _UNICODE
#define STRICT
#define STRICT_TYPED_ITEMIDS
#define CINTERFACE
#define WINVER 0x0600
#define _WIN32_WINNT 0x0600
#define _WIN32_WINDOWS 0x0600
#define _WIN32_IE 0x0700
#define NTDDI_VERSION 0x06000000
#include <windows.h>
#include <commctrl.h>
#include <stdint.h>
#include <uxtheme.h>
#include <string.h>
#include <wchar.h>
#include <windowsx.h>
#include <vsstyle.h>
#include <vssym32.h>
#include <stdarg.h>
#include <oleacc.h>
#include <stdio.h>
void die(char *s)
{
// TODO
}
HWND mainwin;
HWND dtp1, dtp2, dtp3;
void idealsize(HWND dtp, char *n, int *x, int *y)
{
SIZE s;
s.cx = 0;
s.cy = 0;
printf("%s | %I32d ", n, SendMessageW(dtp, DTM_GETIDEALSIZE, 0, (LPARAM) (&s)));
printf("%I32d %I32d\n", s.cx, s.cy);
MoveWindow(dtp, *x, *y, s.cx, s.cy, TRUE);
*y += s.cy;
}
LRESULT CALLBACK wndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
int x, y;
SIZE s;
switch (uMsg) {
case WM_CLOSE:
PostQuitMessage(0);
return 0;
case WM_SIZE:
x = 10;
y = 10;
idealsize(dtp1, "1", &x, &y);
idealsize(dtp2, "2", &x, &y);
idealsize(dtp3, "3", &x, &y);
break;
}
return DefWindowProcW(hwnd, uMsg, wParam, lParam);
}
static HWND makedtp(DWORD style, WCHAR *format)
{
HWND hwnd;
hwnd = CreateWindowExW(WS_EX_CLIENTEDGE,
DATETIMEPICK_CLASSW, L"",
style | WS_TABSTOP | WS_CHILD | WS_VISIBLE,
0, 0, 100, 100,
mainwin, NULL, GetModuleHandle(NULL), NULL);
if (format != NULL)
if (SendMessageW(hwnd, DTM_SETFORMAT, 0, (LPARAM) format) == 0)
die("error applying format string to date/time picker in finishNewDateTimePicker()");
return hwnd;
}
#define GLI(what, buf, n) GetLocaleInfoEx(LOCALE_NAME_USER_DEFAULT, what, buf, n)
HWND makeDateTimePicker(void)
{
WCHAR *date, *time, *datetime;
int ndate, ntime;
int n;
HWND hwnd;
// TODO verify that this always returns a century year
ndate = GLI(LOCALE_SSHORTDATE, NULL, 0);
if (ndate == 0)
die("error getting date string length in uiNewDateTimePicker()");
date = (WCHAR *) malloc(ndate * sizeof (WCHAR));
if (GLI(LOCALE_SSHORTDATE, date, ndate) == 0)
die("error geting date string in uiNewDateTimePicker()");
ntime = GLI(LOCALE_STIMEFORMAT, NULL, 0);
if (ndate == 0)
die("error getting time string length in uiNewDateTimePicker()");
time = (WCHAR *) malloc(ntime * sizeof (WCHAR));
if (GLI(LOCALE_STIMEFORMAT, time, ntime) == 0)
die("error geting time string in uiNewDateTimePicker()");
n = _scwprintf(L"%s %s", date, time);
datetime = (WCHAR *) malloc((n + 1) * sizeof (WCHAR));
snwprintf(datetime, n + 1, L"%s %s", date, time);
hwnd = makedtp(0, datetime);
free(datetime);
free(time);
free(date);
return hwnd;
}
HWND makeDatePicker(void)
{
return makedtp(DTS_SHORTDATECENTURYFORMAT, NULL);
}
HWND makeTimePicker(void)
{
return makedtp(DTS_TIMEFORMAT, NULL);
}
static void makeWindows(void)
{
mainwin = CreateWindowExW(0,
L"mainwin", L"Full Window",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
500, 500,
NULL, NULL, GetModuleHandle(NULL), NULL);
dtp1 = makeDateTimePicker();
dtp2 = makeDatePicker();
dtp3 = makeTimePicker();
}
void initCommonControls(BOOL);
int main(int argc, char *argv[])
{
WNDCLASSW wc;
MSG msg;
HBRUSH b;
initCommonControls(TRUE);
ZeroMemory(&wc, sizeof (WNDCLASSW));
wc.lpszClassName = L"mainwin";
wc.lpfnWndProc = wndProc;
wc.hInstance = GetModuleHandle(NULL);
wc.hIcon = LoadIconW(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursorW(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1);
RegisterClassW(&wc);
makeWindows();
ShowWindow(mainwin, SW_SHOWDEFAULT);
UpdateWindow(mainwin);
while (GetMessageW(&msg, NULL, 0, 0) > 0) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
static const char manifest[] = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">\n<assemblyIdentity\n version=\"1.0.0.0\"\n processorArchitecture=\"*\"\n name=\"CompanyName.ProductName.YourApplication\"\n type=\"win32\"\n/>\n<description>Your application description here.</description>\n<dependency>\n <dependentAssembly>\n <assemblyIdentity\n type=\"win32\"\n name=\"Microsoft.Windows.Common-Controls\"\n version=\"6.0.0.0\"\n processorArchitecture=\"*\"\n publicKeyToken=\"6595b64144ccf1df\"\n language=\"*\"\n />\n </dependentAssembly>\n</dependency>\n</assembly>\n";
static ULONG_PTR comctlManifestCookie;
static HMODULE comctl32;
void initCommonControls(BOOL comctl6)
{
WCHAR temppath[MAX_PATH + 1];
WCHAR filename[MAX_PATH + 1];
HANDLE file;
DWORD nExpected, nGot;
ACTCTX actctx;
HANDLE ac;
INITCOMMONCONTROLSEX icc;
FARPROC f;
// this is listed as WINAPI in both Microsoft's and MinGW's headers, but not on MSDN for some reason
BOOL (*WINAPI ficc)(const LPINITCOMMONCONTROLSEX);
if (comctl6) {
if (GetTempPathW(MAX_PATH + 1, temppath) == 0)
die("getting temporary path for writing manifest file");
if (GetTempFileNameW(temppath, L"manifest", 0, filename) == 0)
die("getting temporary filename for writing manifest file");
file = CreateFileW(filename, GENERIC_WRITE,
0, // don't share while writing
NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (file == NULL)
die("creating manifest file");
nExpected = (sizeof manifest / sizeof manifest[0]) - 1; // - 1 to omit the terminating null character)
if (WriteFile(file, manifest, nExpected, &nGot, NULL) == 0)
die("writing manifest file");
if (nGot != nExpected)
die("short write to manifest file");
if (CloseHandle(file) == 0)
die("closing manifest file (this IS an error here because not doing so will prevent Windows from being able to use the manifest file in an activation context)");
ZeroMemory(&actctx, sizeof (ACTCTX));
actctx.cbSize = sizeof (ACTCTX);
actctx.dwFlags = ACTCTX_FLAG_SET_PROCESS_DEFAULT;
actctx.lpSource = filename;
ac = CreateActCtx(&actctx);
if (ac == INVALID_HANDLE_VALUE)
die("creating activation context for synthesized manifest file");
if (ActivateActCtx(ac, &comctlManifestCookie) == FALSE)
die("activating activation context for synthesized manifest file");
}
ZeroMemory(&icc, sizeof (INITCOMMONCONTROLSEX));
icc.dwSize = sizeof (INITCOMMONCONTROLSEX);
icc.dwICC = ICC_STANDARD_CLASSES | ICC_PROGRESS_CLASS | ICC_TAB_CLASSES | ICC_LISTVIEW_CLASSES | ICC_UPDOWN_CLASS | ICC_BAR_CLASSES | ICC_DATE_CLASSES;
comctl32 = LoadLibraryW(L"comctl32.dll");
if (comctl32 == NULL)
die("loading comctl32.dll");
f = GetProcAddress(comctl32, "InitCommonControlsEx");
if (f == NULL)
die("loading InitCommonControlsEx()");
ficc = (BOOL (*WINAPI)(const LPINITCOMMONCONTROLSEX)) f;
if ((*ficc)(&icc) == FALSE)
die("initializing Common Controls (comctl32.dll)");
}