user10087457
user10087457

Reputation:

Winapi creating a tab menu

I'm trying to make a tab menu, it should have an active state with different styling when a tab is selected, the problem is when starting the program the tabs get selected after two clicks. When displaying the contents of the buttonPressed array in WM_DRAWITEM even, is a delay in changing the value of the active state

case WM_CREATE:

    buttonPressed[0] = 1;
    buttonPressed[1] = 0;
    buttonPressed[2] = 0;
    buttonPressed[3] = 0;

    button1 = CreateWindow("BUTTON","Overview",WS_VISIBLE | WS_CHILD | BS_OWNERDRAW, 0,0,200,50, hwnd , (HMENU) 1 , NULL, NULL);
    button2 = CreateWindow("BUTTON","Send",WS_VISIBLE | WS_CHILD | BS_OWNERDRAW, 200,0,200,50, hwnd , (HMENU) 2, NULL, NULL);
    button3 = CreateWindow("BUTTON","Receive",WS_VISIBLE | WS_CHILD | BS_OWNERDRAW, 400,0,200,50, hwnd , (HMENU) 3, NULL, NULL);
    button4 = CreateWindow("BUTTON","Transactions",WS_VISIBLE | WS_CHILD | BS_OWNERDRAW, 600,0,200,50, hwnd , (HMENU) 4, NULL, NULL);

break;

case WM_DRAWITEM:
        {
            if((wParam == 1 && buttonPressed[0] == 1) ||  (wParam == 2 && buttonPressed[1] == 1) || (wParam == 3 && buttonPressed[2] == 1) || (wParam == 4 && buttonPressed[3] == 1)   ){
                FillRect(Item->hDC, &Item->rcItem, CreateSolidBrush(0x6C6C6C) );
                SetBkMode(Item->hDC, 0x6C6C6C);
                SetTextColor(Item->hDC, RGB(0,0,255));
            }else{
                FillRect(Item->hDC, &Item->rcItem, CreateSolidBrush(0x6C6C6C) );
                SetBkMode(Item->hDC, 0x6C6C6C);
                SetTextColor(Item->hDC, RGB(255,255,255));
            }
                int len;
                len = GetWindowTextLength(Item->hwndItem);
                LPSTR lpBuff;
                lpBuff = new char[len+1];
                GetWindowTextA(Item->hwndItem, lpBuff, len+1);
                DrawTextA(Item->hDC, lpBuff, len, &Item->rcItem, DT_CENTER | DT_VCENTER | DT_WORDBREAK);
        }
break;
case WM_COMMAND:

            switch ( LOWORD(wParam) ){
                case 1:
                   buttonPressed[0] = 1;
                   buttonPressed[1] = 0;
                   buttonPressed[2] = 0;
                   buttonPressed[3] = 0;
                break;
                case 2:
                    buttonPressed[0] = 0;
                   buttonPressed[1] = 1;
                   buttonPressed[2] = 0;
                   buttonPressed[3] = 0;
                break;
                case 3:
                   buttonPressed[0] = 0;
                   buttonPressed[1] = 0;
                   buttonPressed[2] = 1;
                   buttonPressed[3] = 0;
                break;
                case 4:
                   buttonPressed[0] = 0;
                   buttonPressed[1] = 0;
                   buttonPressed[2] = 0;
                   buttonPressed[3] = 1;
                break;

            }

break;

Upvotes: 0

Views: 84

Answers (1)

Remy Lebeau
Remy Lebeau

Reputation: 595402

Your WM_COMMAND handler is not triggering any repaints of the buttons after changing the states in the buttonPressed array. Call InvalidateRect() on each button to trigger a new WM_PAINT message for each button.

Also, you are making the same mistakes in this code (leaking memory and resources, invalid parameter to SetBkMode(), etc) that you made in your earlier code. You are using very few portions of code from the accepted answer, and you are ignoring all of the mistakes that answer pointed out to you.

Try something more like this:

struct ButtonInfo {
    HWND Wnd;
    bool Pressed;
};

ButtonInfo button[4];

...

case WM_CREATE:
    {
        LPCTSTR captions[4] = {TEXT("Overview"), TEXT("Send"), TEXT("Receive"), TEXT("Transactions")};

        for (int i = 0; i < 4; ++i) {
            button[i].Pressed = false;
            button[i].Wnd = CreateWindow(TEXT("BUTTON"), captions[i], WS_VISIBLE | WS_CHILD | BS_OWNERDRAW, i * 200, 0, 200, 50, hwnd, reinterpret_cast<HMENU>(i+1), NULL, NULL);
        }

        button[0].Pressed = true;
    }
    break;

case WM_DRAWITEM:
    {
        LPDRAWITEMSTRUCT Item = reinterpret_cast<LPDRAWITEMSTRUCT>(lParam);

        HFONT hFont = CreateFont(17, 0, 0, 0, FW_NORMAL, 0, 0, 0, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, TEXT("Arial Black"));
        HFONT hOldFont = (HFONT) SelectObject(Item->hDC, hFont);

        HBRUSH hBrush = CreateSolidBrush(RGB(0x6C, 0x6C, 0x6C));
        FillRect(Item->hDC, &Item->rcItem, hBrush);
        DeleteObject(hBrush);

        SetBkMode(Item->hDC, TRANSPARENT);

        int buttonID = wParam;
        if (button[buttonID - 1].Pressed) {
            SetTextColor(Item->hDC, RGB(0,0,255));
        } else {
            SetTextColor(Item->hDC, RGB(255,255,255));
        }

        int len = GetWindowTextLength(Item->hwndItem) + 1;
        LPTSTR lpBuff = new TCHAR[len];
        len = GetWindowText(Item->hwndItem, lpBuff, len);
        DrawText(Item->hDC, lpBuff, len, &Item->rcItem, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
        delete[] lpBuff;

        SelectObject(Item->hDC, hOldFont);
        DeleteObject(hFont);
    }
    break;


case WM_COMMAND:
    {
        int buttonID = LOWORD(wParam);

        int buttonIdx = buttonID - 1;
        for (int i = 0; i < 4; ++i) {
            button[i].Pressed = (i == buttonIdx);
            InvalidateRect(button[i].Wnd, NULL, TRUE);
        }

        switch (buttonID) {
            // perform whatever actions you need based on which button was clicked....
        }
    }
    break;

Upvotes: 1

Related Questions