Как правильно создавать кнопки на WinApi, а также обрабатывать его сообщения - PullRequest
0 голосов
/ 28 мая 2019

Так что моя программа работает, кроме одной вещи, я бы хотел, чтобы моя кнопка 'pushBtn', она же BTN_PUSH_TALK, отправляла сообщение BN_PUSHED или BN_UNPUSHED, чтобы я мог обработать его соответствующим образом.

Выполнение следующих шаговонлайн, а также пробные версии и улучшения, сейчас единственный ответ, который я когда-либо получаю, - это когда я удерживаю / нажимаю кнопку.

       pushBtn = CreateWindowEx(0, L"BUTTON", L"TALK", WS_CHILD | 
       WS_VISIBLE | 
       BS_DEFPUSHBUTTON , 0 , 290 , 50, 50,
   hWnd,(HMENU)BTN_PUSH_TALK, GetModuleHandle(NULL), NULL);

Обработчик (или, по крайней мере, что имеет значение):

 LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM 
lParam)
{
    bool asd;
    switch (message)
    {
    case WM_COMMAND:
    {
        int wmId = LOWORD(wParam);

        // Parse the menu selections:
        switch (wmId)
        {
        case BTN_PUSH_TALK:
            switch (HIWORD(wParam))
            {
            case BN_UNPUSHED:
                if (connected && inputChoiceStr == "Push To Talk") {
                    tplug->setDuck(false);
                }
                break;
            case BN_PUSHED:
                if (connected && inputChoiceStr == "Push To Talk") {
                    tplug->setDuck(true);
                }
                break;
            }
            break;

Я ожидал, что после того, как нажму и удержу кнопку, будет введен случай BN_PUSHED, однако это не так.Отпускаясь, я ожидаю, что будет введен случай BN_UNPUSHED, но это был также не тот случай.case BTN_PUSH_TALK достигается, что означает, что кнопка является идентифицируемой, однако регистр переключения в этом блоке кода никогда не достигается.

Ответы [ 2 ]

1 голос
/ 30 мая 2019

Если я читаю вопрос правильно, ваша цель - получать уведомления, когда пользователь нажимает стандартную кнопку, тогда как стандартное поведение уведомлений для кнопок только отправляет WM_COMMANDs на «щелчки», где щелчок - это вся мышь вниз плюс мышь вверх последовательности.

Исторически для получения уведомлений BN_PUSHED и BN_UNPUSHED в вашем обработчике WM_COMMAND вы должны были использовать стиль окна BS_NOTIFY при создании кнопки. Однако, если вы прочитаете документацию для BN_PUSHED или BN_UNPUSHED, вы увидите

Этот код уведомления предоставляется только для совместимости с 16-разрядными версиями Windows, предшествующими версии 3.0. Приложения должны использовать стиль кнопки BS_OWNERDRAW и структуру DRAWITEMSTRUCT для этой задачи.

Это были очень старые уведомления, которые, насколько я могу судить, не просто устарели, но даже больше не поддерживаются. Вы можете, однако, сделать так, как предлагает документация: использовать кнопку, нарисованную владельцем, то есть кнопку, созданную в стиле BS_OWNERDRAW.

Это оказывается сложнее, чем просто создать кнопку с включенным BS_NOTIFY, поскольку кнопка больше не будет выполнять рисование по умолчанию сама по себе. Учитывая эту добавленную рутинную работу, я бы порекомендовал не делать этого таким образом, если только вы не хотите покрасить свои кнопки в любом случае - если только вам не понадобится нестандартный визуальный вид этих кнопок, а также нестандартное поведение уведомлений. В противном случае, я бы, вероятно, просто сделал бы подклассы Win32, поскольку кто-то другой предложил перехватить WM_LBUTTONDOWN и т. Д., А затем вызвать стандартную кнопку WNDPROC после выполнения некоторых действий над событиями, которые меня волновали.

В любом случае кнопка, нарисованная минимальным владельцем, которая сообщает о событиях кнопки вниз и кнопки вверх, выглядит следующим образом. (Я публикую события кнопки как пользовательские сообщения, но вы можете делать там все, что пожелаете)

#include <windows.h>

#define BTN_ID 101

#define WM_PUSHBUTTONDOWN   WM_APP + 1
#define WM_PUSHBUTTONUP     WM_APP + 2

HINSTANCE g_instance = 0;
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) 
{
    g_instance = hInstance;

    MSG msg = { 0 };                                
    WNDCLASS wc = { 0 };                            
    wc.lpfnWndProc = WndProc;                       
    wc.hInstance = hInstance;                   
    wc.hbrBackground = reinterpret_cast<HBRUSH>(COLOR_BACKGROUND);  
    wc.lpszClassName = L"owner_draw_btn";       

    if (!RegisterClass(&wc))                        
        return -1;                                  

    if (!CreateWindow(wc.lpszClassName, L"foobar",  WS_OVERLAPPEDWINDOW | WS_VISIBLE, 0, 0, 640, 480, 0, 0, hInstance, NULL))                           
        return -1;                                  

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

    return 0;                                                                                   
}

LRESULT HandleDrawItem(HWND hWnd, WPARAM wParam, LPARAM lParam)
{
    auto* dis = reinterpret_cast<DRAWITEMSTRUCT*>(lParam);
    if (dis->CtlType != ODT_BUTTON)
        return 0;

    auto style = (dis->itemState & ODS_SELECTED) ?
        DFCS_BUTTONPUSH | DFCS_PUSHED :
        DFCS_BUTTONPUSH;

    auto rect = &dis->rcItem;
    DrawFrameControl(dis->hDC, rect, DFC_BUTTON, style);

    TCHAR text[512];
    auto n = GetWindowText(dis->hwndItem, text, 512);
    DrawText(dis->hDC, text, n, rect, DT_SINGLELINE | DT_VCENTER | DT_CENTER);

    if (dis->itemAction == ODA_SELECT) {
        PostMessage(
            hWnd,
            (dis->itemState & ODS_SELECTED) ? WM_PUSHBUTTONDOWN : WM_PUSHBUTTONUP,
            dis->CtlID,
            0
        );
    }
    return 0;
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) 
{
    switch (message)
    {
        case WM_CREATE:
            CreateWindow(
                L"button", L"foobar",
                BS_OWNERDRAW | WS_CHILD | WS_VISIBLE, 
                10, 10, 150, 35, hWnd,
                (HMENU) BTN_ID,
                g_instance, 
                0
            );
            return 0;

        case WM_DRAWITEM:
            return HandleDrawItem(hWnd, wParam, lParam);

        case WM_PUSHBUTTONDOWN:
            OutputDebugString(L"Button down event\n");
            break;

        case WM_PUSHBUTTONUP:
            OutputDebugString(L"Button up event\n");
            break;

        case WM_CLOSE:
            PostQuitMessage(0);
            return 0;
    }
    return DefWindowProc(hWnd, message, wParam, lParam);
}
0 голосов
/ 28 мая 2019

Кнопки отправки WM_COMMAND при нажатии. Чтобы получить push-релиз уведомления, вы должны создать подкласс класса кнопки ( SetWindowLongPtr () с GWLP_WNDPROC), а затем обработать WM_LBUTTONDOWN и WM_LBUTTONUP в вашем новом Window Proc.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...