locked
datetimepicker known issue background/text color RRS feed

  • Question

  • hi there.

    my name is catalin and i'm a c++ programmer.

    in plain Win API, no MFC, no ATL,  i have to change background/text color of editing part of datetimepicker.

    i cannot do it because unfortunately

    - there is no WM_CTLCOLORXXX message,

    - there is no child Edit control

    NOTHING.

    i sub-classed window procedure for nothing. it seems that all painting stuff is internally made. i cannot even get the selection so i can correctly draw the text somewhere else ...

    i know this is an old issue but i ask again here.

    is any resolution to this old problem ?

    i hardly wait for an helpful answer.

    regards!

    Friday, August 19, 2016 12:37 PM

All replies

  • Hi cg_progmgr,

    thanks for posting here.

    >>datetimepicker known issue background/text color                          

    For the known issue, please connect to Microsoft to post an issue on it. Your understanding and cooperation.

    >>i have to change background/text color of editing part of datetimepicker.

    For this case, I suggest you use DateTimePicker::BackColor Property to set a value indicating the background color of the DateTimePicker control.

    But note that , setting the BackColor has no effect on the appearance of the DateTimePicker. To set the background color for the drop-down calendar of the DateTimePicker, see the CalendarMonthBackground property.

    You could write a custom control that extends DateTimePicker. Override the BackColor property and the WndProc method.

    Whenever you change the BackColor, don't forget to call the Invalidate() method. This will force the control to redrawn using the new color specified.

    Hope these could be help of you.

    Best Regards,

    Sera Yu


    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.

    Monday, August 22, 2016 6:07 AM
  • hello sera.

    i am sorry you did not understand my request.

    1.

    i said "in plain Win API, no MFC, no ATL,". should i add "no .Net, no Windows forms" etc. for you to understand ?

    when i say "plain Win API" i refer only to Windows procedures, messages and even not C++.

    2.

    and when i refer to "known issue" i refer to a post from this forum

    https://social.msdn.microsoft.com/Forums/en-US/d3d289f5-9978-4143-88ee-4d1a689d07b9/change-background-color-font-of-datetimepicker?forum=vbgeneral

    which contains the following phrase

    Quote" I found the same question (by someone on 31st Aug 2007) and answers by Figo Fei in the forum.
    Figo fei said, "It is truly not possible to directly modify the forecolor of the DateTimePicker which is concealed in its implementation. However, there is a workaround to change its forecolor through own-draw mode in a custom control inherited from dateTimePicker.". And he gave the code which looks like - for me - either VC++ or VC#." end Quote

    now, i don't know if Figo Fei it's still in Microsoft team or not, there are 9 years since then (31st Aug 2007) but when at least on MSFT admits that "It is truly not possible to directly modify the forecolor of the DateTimePicker which is concealed in its implementation" it seems to me as a "known issue" and since it's 9 years old, for a programmer time, it's really an "old known issue" and give me the right to this question "is any resolution to this old problem ?"

    i wonder how the guys who designed version 6.0 of common controls forget about this DateTimePicker "little problem". or they did not forget but ignored ...

    the question "is any resolution to this old problem ?" is still open.

    i still wait for new answers and suggestions.

    regards!

    Monday, August 22, 2016 9:41 AM
  • If you want this:

    It is not possible if Themes are active. The screenshot is taken ion a Windows Server 2008R2. The same Application looks like this:

    If your operating system is non themed the DTM_SETMCCOLOR message can be used:

    https://msdn.microsoft.com/en-us/library/windows/desktop/bb761773(v=vs.85).aspx


    Best regards

    Bordon

    Note: Posted code pieces may not have a good programming style and may not perfect. It is also possible that they do not work in all situations. Code pieces are only indended to explain something particualar.

    Monday, August 22, 2016 12:57 PM
  • If your operating system is non themed the DTM_SETMCCOLOR message can be used:

    https://msdn.microsoft.com/en-us/library/windows/desktop/bb761773(v=vs.85).aspx

    I don't believe it's an operating system dependency.  Don't manifest the application for the v6 common controls.
    Monday, August 22, 2016 3:05 PM
  • I tried many ways to achieve the same thing as you are, but the Date Time control DOES NOT have option to change background or text color. I'm not quite sure why Microsoft doesn't conform this control same as other Windows controls. The only option to change background color is when calendar is pop up.

    Steve

    Monday, August 22, 2016 3:32 PM
  • If your operating system is non themed the DTM_SETMCCOLOR message can be used:

    https://msdn.microsoft.com/en-us/library/windows/desktop/bb761773(v=vs.85).aspx

    I don't believe it's an operating system dependency.  Don't manifest the application for the v6 common controls.

    It is the same with the progress bar, if the OS is themed (means not in classic mode) than the color settings of the progress bar will not work. The color settings only work in classic mode... it is not that new that the control behaviour is different in themed and non themed mode.

    Best regards

    Bordon

    Note: Posted code pieces may not have a good programming style and may not perfect. It is also possible that they do not work in all situations. Code pieces are only indended to explain something particualar.

    Tuesday, August 23, 2016 4:36 AM
  • If your operating system is non themed the DTM_SETMCCOLOR message can be used:

    https://msdn.microsoft.com/en-us/library/windows/desktop/bb761773(v=vs.85).aspx

    I don't believe it's an operating system dependency.  Don't manifest the application for the v6 common controls.


    It is the same with the progress bar, if the OS is themed (means not in classic mode) than the color settings of the progress bar will not work. The color settings only work in classic mode... it is not that new that the control behaviour is different in themed and non themed mode.
    This will be the case with all of the common controls as well as the classic controls that are all themed by the v6 common controls dll.  By not manifestng an app for the v6 common controls dll visual styles will not be used even if you are working with a "themed OS".  I think we're saying the same thing with different words.
    Tuesday, August 23, 2016 4:55 AM
  • I think we're saying the same thing with different words.

    I think you are right... :-)

    But at all, I'm pretty sure the TO is not asking for a solution by removing the v6 common control manifest...


    Best regards

    Bordon

    Note: Posted code pieces may not have a good programming style and may not perfect. It is also possible that they do not work in all situations. Code pieces are only indended to explain something particualar.

    Tuesday, August 23, 2016 5:55 AM
  • hi Bordon.

    thank you for trying but i am not pointing to the calendar.

    forget about calendar part and any calendar related message.

    i am talking about editing part of datetimepicker which is in your pictures "22.08.2016".

    that white/black "22.08.2016" cannot be changed today by any means ! (unless of course you sub-class the control and, in your window procedure, you do your own drawing on WM_PAINT but then you loose selection and you have not the spacing datetimepicker normally has for Date Long or some other custom fields).

    for the sake of your discussion with Steve i say only that no matter what the system is or is not themed, you always have the "magic" function SetWindowTheme (hwndControl, L" ", L" "); which will remove the theme from control and making look in any Windows operating system like controls previous to XP.

    again i am upset because of Microsoft. The only thing to do for them was to send a lousy WM_CTLCOLOREDIT or WM_CTLCOLORSTATIC to parent of DTP before they draw their precious text. they did not do this in 10 years. can you believe that ?

    thanks again for keeping this thread up. maybe some MVP MSFT see it and make a lobby so the team which is responsible for implementing Common Controls will change something, at least for version 7 of Common Controls.

    i am still waiting for suggestions.

    regards!



    • Edited by cg_progmgr Tuesday, August 23, 2016 8:58 AM
    Tuesday, August 23, 2016 8:51 AM
  • for the sake of your discussion with Steve i say only that no matter what the system is or is not themed, you always have the "magic" function SetWindowTheme (hwndControl, L" ", L" "); which will remove the theme from control and making look in any Windows operating system like controls previous to XP.
    Even this "magic" is useless with the datetimepicker control.  It only partially removes the use of visual styles from this control.  If you drop down the calendar you will see that visual styles are still used and the messages to set the calendar control colors are ignored.  Ugh.
    Tuesday, August 23, 2016 10:58 AM
  • hi RLWA32.

    that's a little catch there. Month calendar is another control which exist conform with MSDN only between DTN_DROPDOWN si DTN_CLOSEUP notifications send by DTP to his Parent window.

    so on DTN_DROPDOWN you get the handle to MonthCal control

    case WM_NOTIFY:
        {
        NMHDR                 *pnmhdr = (NMHDR *)lParam;
        HWND                   hwndCtrl = NULL;
        
        if (
            (pnmhdr->code == DTN_DROPDOWN) &&
            ((hwndCtrl = pnmhdr->hwndFrom) != NULL) 
           ) 
            {
            DATETIMEPICKERINFO      dtpi = {0};
                
            dtpi.cbSize = sizeof (DATETIMEPICKERINFO);
                
            DateTime_GetDateTimePickerInfo (hwndCtrl, &dtpi);
             
            SetWindowTheme (dtpi.hwndDropDown, L" ", L" ");
            }
         }

    but it seems that you are right, "magic" doesn't work on child month calendar.

    pfeee Microsoft, you are killing me !


    • Edited by cg_progmgr Tuesday, August 23, 2016 1:58 PM
    Tuesday, August 23, 2016 1:56 PM
  • hi again.

    to rise a little hope for Windows programmers ... at least for calendar.

    i debugged the problem and used Spy++ and dtpi.hwndDropDown , in previous post is not a calendar but an obscure/undocumented Windows DropDown class which has a child a month calendar.

    So in previous post replace

    SetWindowTheme (dtpi.hwndDropDown, L" ", L" ");

    with

    hwndMonthCal = GetWindow (dtpi.hwndDropDown, GW_CHILD);

    SetWindowTheme (hwndMonthCal, L" ", L" ");

    and voila

    "magic" happens again ...

    but what a poor hope ....

    i still cannot do anything about editing part of DTP.

    regards!


    Wednesday, August 24, 2016 1:31 PM
  • hi there Sera.

    it's been 3 months now since i post this thread.

    would you mind give me an honest answer about this issue ?

    could i least hope that will be any change about this in version 7 of Common Controls ?

    can you give me an email so i can write direct to Microsoft team which implemented Windows Common Controls library ?

    best regards.

    Friday, October 21, 2016 1:42 PM
  • You can send WM_PRINT in the subclassing procedure to change the background


    • Edited by Castorix31 Friday, October 21, 2016 2:07 PM
    Friday, October 21, 2016 2:05 PM
  • You can send WM_PRINT in the subclassing procedure =>


    • Edited by Castorix31 Friday, October 21, 2016 2:11 PM
    Friday, October 21, 2016 2:11 PM
  • hi Castorix31.

    what an wonderful picture you have there ! ... it gives me hope.

    "You can send WM_PRINT in the subclassing procedure =>"

    send to what and on which message ? ...

    i suppose that you are on WM_PAINT when you are sending WM_PRINT and cut off the call to default window procedure. or how ? how did you managed ?

    please be more specific with some code attached.

    thank you in advance!

    Saturday, October 22, 2016 12:49 PM
  • Yes, in WM_PAINT.

    I had done a quick test first but I had to improve it because I just noticed that the behaviour of WM_PRINT is different with or without Visual Styles.

    =>

    Includes :

    #include <commctrl.h>
    #pragma comment (lib, "comctl32")
    #include <Shlwapi.h> // DLLGETVERSIONPROC
    
    // To test Visual Styles, comment do disable them
    #pragma comment(linker,"\"/manifestdependency:type='win32' \
    name='Microsoft.Windows.Common-Controls' version='6.0.0.0' \
    processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")

    Functions declarations :

    HWND CreateDTP(HINSTANCE hInstance, HWND hWndParent, RECT* rect, int nID, DWORD dwStyle, WCHAR* wsFormat);
    LRESULT OldDTPProc;
    LRESULT CALLBACK NewDTPProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
    void DTPPaint(HWND hWnd, COLORREF nBkColor, COLORREF nTextColor);
    BOOL g_bThemed = FALSE;

    At startup, to check Visual Styles :

    InitCommonControls();
    
    	HINSTANCE hInstComctl32 = LoadLibrary(TEXT("comctl32.dll"));
    	if (hInstComctl32)
    	{
    		DLLGETVERSIONPROC pfnVersion;
    		pfnVersion = (DLLGETVERSIONPROC)GetProcAddress(hInstComctl32, "DllGetVersion");
    		if (pfnVersion)
    		{
    			DLLVERSIONINFO vi;
    			vi.cbSize = sizeof(DLLVERSIONINFO);
    			if (SUCCEEDED(pfnVersion(&vi)))
    			{
    				if (vi.dwMajorVersion >= 6)
    					g_bThemed = 1;
    			}
    		}
    		FreeLibrary(hInstComctl32);
    	}

    DTP creation :

    RECT rect;
    SetRect(&rect, 10, 10, 150, 25);
    //hWndDTP = CreateDTP(hInst, hWnd, &rect, 10, DTS_TIMEFORMAT, L"tthh':'mm':'ss");
    hWndDTP = CreateDTP(hInst, hWnd, &rect, 10, DTS_LONGDATEFORMAT, L"yyyy'-'MM'-'dd'");
    OldDTPProc = SetWindowLong(hWndDTP, GWL_WNDPROC, (LONG)(WNDPROC)NewDTPProc);

    Functions :

    (I hardcoded background and text color to red and yellow just for testing)

    HWND CreateDTP(HINSTANCE hInstance, HWND hWndParent, RECT* rect, int nID, DWORD dwStyle, WCHAR* wsFormat)
    {
        HWND hWndDTP = NULL;
        hWndDTP = CreateWindowEx(WS_EX_CLIENTEDGE, DATETIMEPICK_CLASS, NULL, WS_CHILD | WS_VISIBLE | WS_TABSTOP | dwStyle,
            rect->left,    rect->top, rect->right,    rect->bottom, hWndParent, (HMENU)IntToPtr(nID),    hInstance, NULL);
        if (hWndDTP)
        {
            //DateTime_SetSystemtime(hWndDTP, GDT_NONE, NULL);
            DateTime_SetFormat(hWndDTP, wsFormat);
        }
        return hWndDTP;
    }

    LRESULT CALLBACK NewDTPProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { static COLORREF nBkColor = RGB(255, 0, 0); static COLORREF nTextColor = RGB(255, 255, 0); switch (uMsg) { case WM_PAINT: { PAINTSTRUCT ps; BeginPaint(hWnd, &ps); DTPPaint(hWnd, nBkColor, nTextColor); EndPaint(hWnd, &ps); return 0; } break; } return(CallWindowProc((WNDPROC)OldDTPProc, hWnd, uMsg, wParam, lParam)); } void DTPPaint(HWND hWnd, COLORREF nBkColor, COLORREF nTextColor) { RECT rect; GetWindowRect(hWnd, &rect); MapWindowPoints(NULL, hWnd, (LPPOINT)&rect, 2); long nWidth = rect.right - rect.left, nHeight = rect.bottom - rect.top; HDC hDC = GetDC(hWnd); HDC hDCMem = CreateCompatibleDC(hDC); int nX = nWidth, nY = nHeight; BITMAPINFO bi = { 0 }; bi.bmiHeader.biSize = sizeof(bi.bmiHeader); bi.bmiHeader.biWidth = nX; bi.bmiHeader.biHeight = nY; bi.bmiHeader.biPlanes = 1; bi.bmiHeader.biBitCount = 32; bi.bmiHeader.biCompression = BI_RGB; BYTE *pbBitmap; HBITMAP hBitmap = CreateDIBSection(hDCMem, &bi, DIB_RGB_COLORS, (void**)&pbBitmap, NULL, 0); if (hBitmap) { HBITMAP hBitmapOld = (HBITMAP)SelectObject(hDCMem, hBitmap); SendMessage(hWnd, WM_PRINT, (WPARAM)hDCMem, PRF_CLIENT | PRF_CHILDREN | PRF_NONCLIENT | PRF_ERASEBKGND); //SendMessage(hWnd, WM_PRINTCLIENT, (WPARAM)hDCMem, PRF_CLIENT | PRF_CHILDREN | PRF_NONCLIENT); RGBQUAD *pRGB; LONG nPixels; int nPixelX = 0, nPixelY = 0; DWORD nTextColorOrig = GetSysColor(COLOR_WINDOWTEXT); DWORD nBkColorOrig = GetSysColor(COLOR_WINDOW); //BOOL bThemed = IsThemeActive() && IsAppThemed(); int nXShift = 0; if (g_bThemed) nXShift = GetSystemMetrics(SM_CXVSCROLL); else nXShift = GetSystemMetrics(SM_CXVSCROLL) + GetSystemMetrics(SM_CXEDGE); for (pRGB = (RGBQUAD *)pbBitmap, nPixels = nX * nY; nPixels > 0; ++pRGB, --nPixels) { ULONG* pSrc = (ULONG*)pRGB; ULONG nRed = GetRValue(*pSrc); ULONG nGreen = GetGValue(*pSrc); ULONG nBlue = GetBValue(*pSrc); BOOL bTestRightPart = FALSE, bTest = FALSE; if (!g_bThemed) bTestRightPart = TRUE; if (g_bThemed) bTestRightPart = (GetWindowLong(hWnd, GWL_STYLE) & DTS_TIMEFORMAT) ? FALSE : TRUE; bTest = (bTestRightPart ? (nPixelX < nX - nXShift) : TRUE); if (nRed == GetRValue(nTextColorOrig) && nGreen == GetGValue(nTextColorOrig) && nBlue == GetBValue(nTextColorOrig)) { if (bTest) { pRGB->rgbRed = GetRValue(nTextColor); pRGB->rgbGreen = GetGValue(nTextColor); pRGB->rgbBlue = GetBValue(nTextColor); } } if (nRed == GetRValue(nBkColorOrig) && nGreen == GetGValue(nBkColorOrig) && nBlue == GetBValue(nBkColorOrig)) { if (bTest) { pRGB->rgbRed = GetRValue(nBkColor); pRGB->rgbGreen = GetGValue(nBkColor); pRGB->rgbBlue = GetBValue(nBkColor); } } nPixelX += 1; if (nPixelX >= nX) { nPixelY += 1; nPixelX = 0; } } BitBlt(hDC, rect.left, rect.top, nWidth, nHeight, hDCMem, 0, 0, SRCCOPY); SelectObject(hDCMem, hBitmapOld); DeleteObject(hBitmap); } DeleteDC(hDCMem); ReleaseDC(hWnd, hDC); }



    • Edited by Castorix31 Saturday, October 22, 2016 4:23 PM
    Saturday, October 22, 2016 4:21 PM
  • man,

    first thing first: thank you for sharing this.

    but it's quite a hack, it's almost there and it's the only solution i came up with after some hard trial and error tests ... 

    also the solution don't deals with checkbox they have for DTS_SHOWNONE, not to mention arrow button.

    i approached the problem using a similar mode, cutting off your BeginPaint and EndPaint because the most controls can be fooled by passing WM_PAINT to their default procedure with a HDC like WPARAM (in your case hDCMem).

    that is why i am so mad on Microsoft,

    we need to invent hallucinating modes of doing things when they can simply send a message (in our case WM_CTLCOLORXYZ).

    i still wait that Sera (or other MSFT) answer so i can directly question WINDOWS Common Controls team about this problem.

    again Castorix31, thank you for sharing.


    • Edited by cg_progmgr Sunday, October 23, 2016 8:19 AM
    Sunday, October 23, 2016 8:03 AM