Определите, когда дочерний элемент управления CButton добавляется в CDialog с помощью WM_PARENTNOTIFY - PullRequest
3 голосов
/ 07 октября 2019

Работа с:

  • Visual Studio 2017;
  • MFC, C ++.

Я пытаюсь изменить проект MFC дляCDialog производный класс для определения, когда к нему добавлен дочерний элемент управления (CButton производные классы). Желательно получить дескриптор (HWND) для этих CButtons для дальнейшей их обработки, как я могу получить из родительского диалогового окна со следующим кодом:

HWND handleParent = ::GetTopWindow(this->GetSafeHwnd());

Я прочиталодин способ сделать это, обработав WM_PARENTNOTIFY, но я не могу запустить его каким-либо образом, используя функцию основного события: OnParentNotify (или WindowProc из некоторых источников).

Я сделал следующее, по крайней мере для OnParentNotify:

  1. добавил экспорт сообщения:

ON_WM_PARENTNOTIFY ()

в функции-члене DerivedDialog::OnInitDialog() удален стиль WS_EX_NOPARENTNOTIFY из всех возможных дескрипторов управления после CDialog::OnInitDialog() строки кода:
CDialog::OnInitDialog();

HWND hwnd = ::GetTopWindow(this->GetSafeHwnd());
while (hwnd)
{
    LONG lExStyle;
    lExStyle = GetWindowLong(hwnd, GWL_EXSTYLE);

    if (lExStyle & WS_EX_NOPARENTNOTIFY)
    {
        lExStyle &= ~WS_EX_NOPARENTNOTIFY;
        SetWindowLong(hwnd, GWL_EXSTYLE, lExStyle);
    }

    hwnd = ::GetNextWindow(hwnd, GW_HWNDNEXT);
}
объявленная и определенная функция только для того, чтобы увидеть, вызывается ли она:
OnParentNotify(UINT message, LPARAM lParam)
{

CDialog::OnParentNotify(message, lParam)
{
    switch (LOWORD(message))
    {
        case WM_CREATE:
        {
            int a = 3;
            int b = 2;
        }
        break;
        case WM_PARENTNOTIFY:
        {
            int c = 1;
            int d = 0;
        }
    }
}

К сожалению, только WM_CREATE вызывается один раз (не думайте, что она связанаили правильно, так как у меня есть 2 кнопки, которые должны быть добавлены в диалоге .. так что я ожидаю 2 WM_CREATES, если это так ??).

Я действительно не уверен, как вызвать это сообщение для вызова. Любой совет будет очень полезным!

1 Ответ

1 голос
/ 07 октября 2019

Из Документация MSDN :

Система также отправляет сообщения WM_PARENTNOTIFY, когда создает и уничтожает окно, но не для элементов управления, созданных из шаблона диалогового окна. Система предотвращает эти сообщения, указывая стиль WS_EX_NOPARENTNOTIFY при создании элементов управления. Приложение не может переопределить это поведение по умолчанию, если оно не создает свои собственные элементы управления для диалогового окна.

В соответствии с этим все кнопки, созданные из шаблона диалога, не получат WM_PARENTNOTIFY. (ваш код в DerivedDialog::OnInitDialog() не влияет).

WM_PARENTNOTIFY работает, если вы динамически создаете кнопку (или дочерний элемент управления).

Пример (добавьте к существующему коду):

  1. Добавить CButton m_sampleButton элемент в заголовок диалогового окна.
  2. Добавить создание в OnInitDialog код

    m_sampleButton.Create(L"Sample", WS_CHILD|WS_VISIBLE, CRect(10, 10, 100, 100), this, 10);
    

Редактировать: (на основе @Adrian comment)

Альтернативным решением может быть переопределение функции PreSubclassWindow производного класса вашей кнопки и отправка пользовательского сообщения в родительское окно.

Класс кнопок:

#define CUSTOM_CREATE_NOTIFY WM_USER+1001 // (add to header file)

void CCustomButton::PreSubclassWindow()
{   
    CButton::PreSubclassWindow();

    GetParent()->PostMessage(CUSTOM_CREATE_NOTIFY, (WPARAM)m_hWnd);
}

Класс диалогов:

// add to message map
ON_MESSAGE(CUSTOM_CREATE_NOTIFY, OnCustomNotify)

LRESULT CMFCApplication2Dlg::OnCustomNotify(WPARAM wParam, LPARAM)
{   
    // wparam is the HWND to the button.

    return 0;
}
...