Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

How to handle notification from date picker control

I can construct and show a date picker control. I can change the date displayed in the control by clicking on it.

image

The problem is that I cannot get the notification when the date is changed.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

Here is the complete, minimal code for an application showing the problem. The intention to for the console to show a message when the notification is received, either in the message loop or in the window message handler.

#include <windows.h>
#include <iostream>
#include "commctrl.h"

// Add common controls V6 to manifest
#pragma comment(linker, "/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")

// Message handler
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg)
    {
    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;

    case WM_PAINT:
    {
        PAINTSTRUCT ps;
        HDC hdc = BeginPaint(hwnd, &ps);
        FillRect(hdc, &ps.rcPaint, (HBRUSH)(COLOR_WINDOW + 1));
        EndPaint(hwnd, &ps);
    }
    return 0;

    case DTN_DATETIMECHANGE:
        std::cout << " date change\n";
        return 0;
    }
    return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

HWND ConstructMainWindow()
{
    // Register the window class.
    const char CLASS_NAME[] = "Sample Window Class";

    WNDCLASSA wc = {};
    wc.lpfnWndProc = WindowProc;
    wc.hInstance = NULL;
    wc.lpszClassName = CLASS_NAME;

    RegisterClassA(&wc);

    // Create the window.

    HWND hwnd = CreateWindowExA(
        0,                          // Optional window styles.
        CLASS_NAME,                 // Window class
        "Date Picker Test", // Window text
        WS_OVERLAPPEDWINDOW,        // Window style

        // Size and position
        CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,

        NULL, // Parent window
        NULL, NULL, NULL);
    if (hwnd == NULL)
    {
        std::cout << "main window failed\n";
        exit(1);
    }

    return hwnd;
}

void ConstructDatePicker(HWND main)
{
    // initialize date picker control
    INITCOMMONCONTROLSEX icex;
    icex.dwSize = sizeof(icex);
    icex.dwICC = ICC_DATE_CLASSES;
    if (!InitCommonControlsEx(&icex))
        std::cout << "InitCommonControlsEx failed\n";

    // send messages to WindowProc
    WNDCLASSA wc = {};
    wc.lpfnWndProc = &WindowProc;
    wc.hInstance = NULL;
    wc.lpszClassName = "DateTime";
    RegisterClassA(&wc);

    CreateWindowExA(0,
                    DATETIMEPICK_CLASSA,
                    "DateTime",
                    WS_BORDER | WS_CHILD | WS_VISIBLE | DTS_SHOWNONE,
                    30, 30, 200, 30,
                    main,
                    NULL,
                    NULL,
                    NULL);
}

int main()
{
    HWND hwnd = ConstructMainWindow();

    ConstructDatePicker(hwnd);

    ShowWindow(hwnd, 1);

    // Run the message loop.

    MSG msg = {};
    while (GetMessage(&msg, NULL, 0, 0) > 0)
    {
        if( msg.message == DTN_DATETIMECHANGE)
            std::cout << "message " << msg.message << "\n";
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return 0;
}

>Solution :

DO NOT call RegisterClass() for system-provided classes. They are already registered by the OS. You are not supposed to register a custom WindowProc for system classes. If you want to hook a system-provided UI control, use SetWindowLongPtr(GWLP_WNDPROC) or SetWindowSubclass() instead. See Subclassing Controls on MSDN.

However, that being said, there is no need to do that in this case, because the DTN_DATETIMECHANGE notification is sent to the DTP’s parent window (ie, your main window), which you already have a WindowProc registered for. The reason you are not seeing the notification is because you are catching it incorrectly. DTN_DATETIMECHANGE (-759) is not the actual message code, so your switch never jumps to that case. The notification is actually wrapped inside of a WM_NOTIFY message (which you would have known if you had read the documentation):

Sent by a date and time picker (DTP) control whenever a change occurs. This notification code is sent in the form of a WM_NOTIFY message.

So, try this instead:

#include <windows.h>
#include <iostream>
#include "commctrl.h"

// Add common controls V6 to manifest
#pragma comment(linker, "/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")

// Message handler
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg)
    {
        case WM_CREATE:
            CreateWindowExA(0,
                    DATETIMEPICK_CLASSA,
                    "DateTime",
                    WS_BORDER | WS_CHILD | WS_VISIBLE | DTS_SHOWNONE,
                    30, 30, 200, 30,
                    hwnd,
                    NULL,
                    NULL,
                    NULL);
            return 0;

        case WM_DESTROY:
            PostQuitMessage(0);
            return 0;

        case WM_PAINT:
        {
            PAINTSTRUCT ps;
            HDC hdc = BeginPaint(hwnd, &ps);
            FillRect(hdc, &ps.rcPaint, reinterpret_cast<HBRUSH>(COLOR_WINDOW + 1));
            EndPaint(hwnd, &ps);
        }
        return 0;

        case WM_NOTIFY:
        {
            NMHDR *pnmhdr = reinterpret_cast<NMHDR*>(lParam);
            if (pnmhdr->code == DTN_DATETIMECHANGE)
            {
                LPNMDATETIMECHANGE lpChange = reinterpret_castt<LPNMDATETIMECHANGE>(lParam);
                // use lpChange->dwFlags and lpChange->st as needed...
                std::cout << " date change\n";
            }
        }
        return 0;
    }

    return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

HWND ConstructMainWindow()
{
    // Register the window class.
    const char CLASS_NAME[] = "Sample Window Class";

    WNDCLASSA wc = {};
    wc.lpfnWndProc = WindowProc;
    wc.lpszClassName = CLASS_NAME;

    if (RegisterClassA(&wc) == NULL)
    {
        std::cout << "main window register class failed\n";
        exit(1);
    }

    // Create the window.

    HWND hwnd = CreateWindowExA(
        0,                        // Optional window styles.
        CLASS_NAME,              // Window class
        "Date Picker Test", // Window text
        WS_OVERLAPPEDWINDOW,        // Window style

        // Size and position
        CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,

        NULL, // Parent window
        NULL, NULL, NULL);
    if (hwnd == NULL)
    {
        std::cout << "main window failed\n";
        exit(1);
    }

    return hwnd;
}

int main()
{
    // initialize date picker control
    INITCOMMONCONTROLSEX icex;
    icex.dwSize = sizeof(icex);
    icex.dwICC = ICC_DATE_CLASSES;
    if (!InitCommonControlsEx(&icex))
    {
        std::cout << "InitCommonControlsEx failed\n";
        return 1;
    }

    HWND hwnd = ConstructMainWindow();

    ShowWindow(hwnd, 1);

    // Run the message loop.

    MSG msg = {};
    while (GetMessage(&msg, NULL, 0, 0) > 0)
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return 0;
}
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading