如何在winApi上正确创建按钮以及处理其消息

时间:2019-05-28 13:51:52

标签: c++ winapi button

因此,我的程序可以工作,除了一件事情,我想为我的按钮'pushBtn'发送一个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 个答案:

答案 0 :(得分:1)

如果我的问题没对,您的目标是在用户最初按下标准按钮时获得通知,而按钮的标准通知行为仅在“ clicks”上发布WM_COMMANDs,而单击就是整个鼠标向下加鼠标向上的顺序。

从历史上看,为了在WM_COMMAND处理程序中获取BN_PUSHED和BN_UNPUSHED通知,创建按钮时必须使用BS_NOTIFY窗口样式。但是,如果您阅读了BN_PUSHED或BN_UNPUSHED的文档,则会看到

  

仅提供此通知代码是为了与3.0版之前的16位版本的Windows兼容。应用程序应使用BS_OWNERDRAW按钮样式和DRAWITEMSTRUCT结构来完成此任务。

这些都是非常古老的通知,据我所知,它们不仅被弃用,甚至不再得到支持。但是,您可以按照文档中的建议进行操作:使用所有者绘制的按钮,即以BS_OWNERDRAW样式创建的按钮。

事实证明,这比仅在启用BS_NOTIFY的情况下创建按钮要困难得多,因为该按钮将不再自行执行默认绘制。考虑到这种繁琐的工作,我建议不要以这种方式进行操作,除非您仍然想要自定义绘画按钮的颜色-除非您碰巧希望这些按钮具有某种非标准的视觉外观以及非标准的通知行为。否则,我可能会像其他人建议捕获WM_LBUTTONDOWN等一样,进行Win32子类化,然后在对我关心的事件进行一些操作后调用标准按钮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);
}

答案 1 :(得分:0)

按钮在点击时发送WM_COMMAND。要获得推送/释放通知,您必须将按钮类(SetWindowLongPtr()和GWLP_WNDPROC)作为子类,然后在新的Window Proc中处理WM_LBUTTONDOWNWM_LBUTTONUP