簡體   English   中英

如何在winApi上正確創建按鈕以及處理其消息

[英]How to correctly create push buttons on winApi as well as Handle its messages

因此,我的程序可以正常工作,除了一件事情,我想為按鈕'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案例,但事實並非如此。 達到了BTN_PUSH_TALK的情況,這意味着該按鈕是可識別的,但是,從未達到此代碼塊內的開關條件。

單擊后,按鈕發送WM_COMMAND 要獲得推送/釋放通知,您必須將按鈕類( SetWindowLongPtr()與GWLP_WNDPROC)作為子類,然后在新的Windows Proc中處理WM_LBUTTONDOWNWM_LBUTTONUP

如果我沒看錯,您的目標是在用戶最初按下標准按鈕時獲得通知,而按鈕的標准通知行為僅在“點擊”上發布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);
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM