Как поместить элемент управления EDIT в пользовательское всплывающее окно с помощью Win32 API? - PullRequest
0 голосов
/ 14 октября 2018

Я пытаюсь добавить элемент управления EDIT в окно, используемое в качестве раскрывающегося списка для пользовательского элемента управления, похожего на комбинированный список.Первоначально это раскрывающееся окно было реализовано как дочернее (WS_CHILD) окно рабочего стола, которое аналогично окну «ComboLbox», используемому настоящим списком.Это сработало просто отлично, однако окно EDIT, похоже, просто отказывается принимать фокус, когда оно помещается в такое выпадающее окно.Т.е. он включен и реагирует, например, на щелчки правой кнопкой мыши, но щелкнуть по нему или вызвать SetFocus() не удается (последний устанавливает последнюю ошибку на ERROR_INVALID_PARAMETER).

Из-за этого, а также из-заСпособ реализации пользовательских всплывающих окон во многих примерах, включая образец fakemenu Рэймонда Чена , я изменил в раскрывающейся реализации на WS_POPUP с основным окном приложения в качестве владельца.Это имеет известную проблему с кражей активации из окна владельца, когда отображается всплывающее окно, однако это можно устранить, возвращая обработчик MA_NOACTIVATE из WM_MOUSEACTIVATE для всплывающего окна, и оно действительно изначально хорошо работает, то есть окно владельца сохраняет активациюкогда всплывающее окно появляется.Но как только я щелкаю элемент управления EDIT внутри всплывающего окна, он вызывает из своего стандартного окна proc SetFocus(), чтобы установить фокус на себя, что деактивирует родительское окно.

Мой вопрос: как я могу это сделать?предотвратить это?Я знаю, что это можно сделать, потому что WinForms ToolStripManager позволяет разрешить редактирование текста в раскрывающемся списке без деактивации родительского окна, а также использует стиль WS_POPUP для всплывающего окна.Но как это сделать?

1 Ответ

0 голосов
/ 15 октября 2018

В комментариях было предложено решение "предотвратить отображение окна хоста неактивным, обработав WM_NCACTIVATE" Это должно работать, как показано в примере ниже.

Когда окно менюоткрытое окно хоста (HostProc) получит сообщение WM_NCACTIVATE.Хост будет искать "menuclass", если класс меню найден, то хост вернет DefWindowProc(hwnd, WM_NCACTIVATE, TRUE, lparam);, чтобы строка заголовка окна хоста не отображалась неактивно.

Вам также нужно обработать WM_NCACTIVATE в окне фальшивого меню,Когда окно меню выходит из фокуса, MenuProc получает WM_NCACTIVATE, в этот момент меню может закрыться.

#include <windows.h>

const wchar_t* menuclass = L"menuclass";

LRESULT CALLBACK MenuProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
    switch(msg)
    {
    case WM_CREATE:
        CreateWindow(L"Edit", NULL, WS_CHILD | WS_VISIBLE | WS_BORDER, 10, 10, 160, 30,
            hwnd, NULL, NULL, NULL);
        break;

    case WM_NCACTIVATE:
    {
        if(!wparam)
        {
            //close the menu if its losing focus
            PostMessage(hwnd, WM_CLOSE, 0, 0);

            //tell parent to paint inactive, if user clicked on a different program
            POINT pt;
            GetCursorPos(&pt);
            HWND hit = WindowFromPoint(pt);
            HWND hparent = GetParent(hwnd);
            if(hit != hparent && !IsChild(hparent, hit))
                DefWindowProc(hparent, WM_NCACTIVATE, FALSE, 0);
        }
        break;
    }

    case WM_LBUTTONDOWN:
        PostMessage(hwnd, WM_CLOSE, 0, 0);
        break;
    //also handles other mouse/key messages associated with a menu...
    }

    return DefWindowProc(hwnd, msg, wparam, lparam);
}

LRESULT CALLBACK HostProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
    switch(msg)
    {
    case WM_NCACTIVATE:
        //paint the window as active when custom menu starts
        if(!wparam && FindWindow(menuclass, NULL))
            return DefWindowProc(hwnd, WM_NCACTIVATE, TRUE, lparam);
        break;
    case WM_RBUTTONUP:
    {
        //show the custom menu
        POINT pt;
        GetCursorPos(&pt);
        CreateWindow(menuclass, NULL, WS_VISIBLE | WS_POPUP | WS_BORDER,
            pt.x, pt.y, 200, 400, hwnd, 0, 0, 0);
        return 0;
    }
    case WM_DESTROY: 
        PostQuitMessage(0);
        return 0;
    }

    return DefWindowProc(hwnd, msg, wparam, lparam);
}

int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, LPTSTR, int)
{
    WNDCLASSEX wcex = { sizeof(WNDCLASSEX) };
    wcex.hInstance = hInstance;
    wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
    wcex.lpfnWndProc = HostProc;
    wcex.lpszClassName = L"hostwnd";
    RegisterClassEx(&wcex);

    wcex.lpfnWndProc = MenuProc;
    wcex.lpszClassName = menuclass;
    RegisterClassEx(&wcex);

    CreateWindow(L"hostwnd", L"Right click for menu ...", 
        WS_VISIBLE | WS_OVERLAPPEDWINDOW, 0, 0, 600, 400, 0, 0, hInstance, 0);

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

    return (int)msg.wParam;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...