问题
I have enabled Visual styles for my application:
#pragma comment( linker, "/manifestdependency:\"type='win32' \
name='Microsoft.Windows.Common-Controls' version='6.0.0.0' \
processorArchitecture='*' publicKeyToken='6595b64144ccf1df' \
language='*'\"")
I can set font for the date in the edit control with following approach:
HFONT hf = (HFONT)SendMessage(hwndDateTimePicker, WM_GETFONT, (WPARAM)0, (LPARAM)0);
if (hf != NULL)
{
LOGFONT lf = { 0 };
GetObject(hf, sizeof(LOGFONT), &lf);
lf.lfWeight = FW_BOLD;
lf.lfUnderline = TRUE;
hf = CreateFontIndirect(&lf);
SendMessage(GetDlgItem(hDlg, IDC_DATETIMEPICKER1), WM_SETFONT
(WPARAM)hf, (LPARAM)TRUE);
}
However, trying to use GetDC and SetTextColor (for example) does not work.
Below image illustrates my goal (color is changed to yellow).
I have tried subclassing the control, but tjat failed. Here is the code, in case you can spot a mistake:
LRESULT CALLBACK Decimalni(HWND hwnd, UINT message,
WPARAM wParam, LPARAM lParam,
UINT_PTR uIdSubclass, DWORD_PTR dwRefData)
{
switch (message)
{
case WM_CTLCOLOREDIT:
return (LRESULT)((HBRUSH)GetStockObject(GRAY_BRUSH));
case WM_NCDESTROY:
::RemoveWindowSubclass(hwnd, Decimalni, 0);
return DefSubclassProc(hwnd, message, wParam, lParam);
break;
}
return ::DefSubclassProc(hwnd, message, wParam, lParam);
}
// in WM_INITDIALOG
SetWindowSubclass(hwndDTP, Decimalni, 0, 0 );
QUESTION:
Is there a workaround for my problem?
Maybe there is a way to get the handle of the edit control and subclass it, for example? Just a thought...
EDIT:
This is the best I could have done:
// subclass procedure for date time picker
LRESULT CALLBACK DTP(HWND hwnd, UINT message,
WPARAM wParam, LPARAM lParam,
UINT_PTR uIdSubclass, DWORD_PTR dwRefData)
{
switch (message)
{
case WM_PAINT:
{
PAINTSTRUCT ps = { 0 };
HDC hdc = BeginPaint(hwnd, &ps);
RECT rcClient = { 0 };
GetClientRect(hwnd, &rcClient);
// Fill client area with desired brush, I used light gray as an example
FillRect(hdc, &rcClient, (HBRUSH)GetStockObject(LTGRAY_BRUSH));
BITMAPINFO bmi;
// Create a memory DC
HDC memDC = CreateCompatibleDC(hdc);
// Create a DIB header for parent
memset(&bmi, 0, sizeof(bmi));
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmi.bmiHeader.biWidth = rcClient.right - rcClient.left;
bmi.bmiHeader.biHeight = rcClient.bottom - rcClient.top;
bmi.bmiHeader.biBitCount = 24;
bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biCompression = BI_RGB;
// Create a DIB bitmap
HBITMAP tempBmp = CreateDIBSection(0, &bmi, DIB_RGB_COLORS, 0, 0, 0);
// Select tempBmp onto DC to force size and DIB change on the DC
HBITMAP oldBmp = (HBITMAP)SelectObject(memDC, tempBmp);
// Okay get datetime picker to draw on our memory DC
DefSubclassProc(hwnd, WM_PRINTCLIENT, (WPARAM)memDC, (LPARAM)(PRF_CLIENT));
// Transfer the memory DC onto datetime picker DC excluding default white color
TransparentBlt(hdc, 0, 0, rcClient.right - rcClient.left, rcClient.bottom - rcClient.top,
memDC, 0, 0, rcClient.right - rcClient.left, rcClient.bottom - rcClient.top, GetSysColor(COLOR_WINDOW));
// cleanup
SelectObject(memDC, oldBmp);
DeleteObject(tempBmp);
DeleteDC(memDC);
EndPaint(hwnd, &ps);
}
return 0L;
case WM_NCDESTROY:
::RemoveWindowSubclass(hwnd, DTP, 0);
return DefSubclassProc(hwnd, message, wParam, lParam);
}
return ::DefSubclassProc(hwnd, message, wParam, lParam);
}
In main windiw/dialog, just subclass the DateTime picker:
SetWindowSubclass(hwndOfYourDateTimePicker, DTP, 0, 0);
NEW QUESTIONS:
- You will notice that dropdown button is not visually appealing. Is there a way to correct this?
- ClearType font might give some artifacts, is there a way to solve this?
回答1:
Results of my experiments with catching WM_CTLCOLORxxx in the parent window
The code is below. Without any arguments it merely prints which WM_CTLCOLORxxx messages comes in. With arguments it tries to change both the control color and the text background color (to differnt things, but based on your them for simplicity).
Windows 7, no visual styles/Common Controls 5: no WM_CTLCOLORxx messages; no change in colors
Windows 7, visual styles/Common Controls 6: several WM_CTLCOLORSTATIC messages, but setting colors seems to have no effect
wine: one WM_CTLCOLREDIT message, returned brush is applied but text background color is not
This is all with a 32-bit binary; I doubt using a 64-bit binary would change anything (at least, I hope not).
So merely checking the parent window for a WM_CTLCOLORxxx message won't work. This answer doesn't answer the question, but there's surely room for more experimentation (perhaps more subclassing tests?).
I looked at the visual styles/Common Controls 6 setup in Spy++ on Windows 7 and I didn't see any children of the date-time picker.
Hopefully this helps for now.
// 17 february 2015
#define UNICODE
#define _UNICODE
#define STRICT
#define STRICT_TYPED_ITEMIDS
#define CINTERFACE
#define COBJMACROS
// get Windows version right; right now Windows XP
#define WINVER 0x0501
#define _WIN32_WINNT 0x0501
#define _WIN32_WINDOWS 0x0501 /* according to Microsoft's winperf.h */
#define _WIN32_IE 0x0600 /* according to Microsoft's sdkddkver.h */
#define NTDDI_VERSION 0x05010000 /* according to Microsoft's sdkddkver.h */
#include <windows.h>
#include <commctrl.h>
#include <stdio.h>
HWND dtp;
BOOL returnColors = FALSE;
LRESULT CALLBACK wndproc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg) {
case WM_CLOSE:
PostQuitMessage(0);
return 0;
#define CTLCOLOR(which) \
case which: \
printf("%s %p\n", #which, (HWND) lParam); \
if (returnColors) { \
SetBkColor((HDC) wParam, GetSysColor(COLOR_ACTIVECAPTION)); \
return (LRESULT) GetSysColorBrush(COLOR_GRADIENTACTIVECAPTION); \
} \
break; /* fall through to DefWindowProc() */
CTLCOLOR(WM_CTLCOLORMSGBOX)
CTLCOLOR(WM_CTLCOLOREDIT)
CTLCOLOR(WM_CTLCOLORLISTBOX)
CTLCOLOR(WM_CTLCOLORBTN)
CTLCOLOR(WM_CTLCOLORDLG)
CTLCOLOR(WM_CTLCOLORSCROLLBAR)
CTLCOLOR(WM_CTLCOLORSTATIC)
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
int main(int argc, char *argv[])
{
INITCOMMONCONTROLSEX icc;
WNDCLASSW wc;
HWND mainwin;
MSG msg;
returnColors = argc > 1;
ZeroMemory(&icc, sizeof (INITCOMMONCONTROLSEX));
icc.dwSize = sizeof (INITCOMMONCONTROLSEX);
icc.dwICC = ICC_DATE_CLASSES;
if (InitCommonControlsEx(&icc) == 0) {
fprintf(stderr, "InitCommonControlsEx() failed: %I32u\n", GetLastError());
return 1;
}
ZeroMemory(&wc, sizeof (WNDCLASSW));
wc.lpszClassName = L"mainwin";
wc.lpfnWndProc = wndproc;
wc.hIcon = LoadIconW(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursorW(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1);
wc.hInstance = GetModuleHandle(NULL);
if (RegisterClassW(&wc) == 0) {
fprintf(stderr, "RegisterClassW() failed: %I32u\n", GetLastError());
return 1;
}
mainwin = CreateWindowExW(0,
L"mainwin", L"Main Window",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
320, 240,
NULL, NULL, GetModuleHandle(NULL), NULL);
if (mainwin == NULL) {
fprintf(stderr, "create main window failed: %I32u", GetLastError());
return 1;
}
dtp = CreateWindowExW(0,
DATETIMEPICK_CLASSW, L"",
DTS_LONGDATEFORMAT | WS_CHILD | WS_VISIBLE,
20, 20, 200, 180,
mainwin, NULL, GetModuleHandle(NULL), NULL);
if (dtp == NULL) {
fprintf(stderr, "create date-time picker failed: %I32u\n", GetLastError());
return 1;
}
printf("dtp %p\n", dtp);
ShowWindow(mainwin, SW_SHOWDEFAULT);
UpdateWindow(mainwin);
while (GetMessageW(&msg, NULL, 0, 0) > 0) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
来源:https://stackoverflow.com/questions/28511802/date-and-time-picker-with-visual-styles-enabled-change-background-color-of-the