Date and time picker with Visual styles enabled-> change background color of the title

瘦欲@ 提交于 2019-12-13 03:59:10

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!