ZKJohan
ZKJohan

Reputation: 11

How to color parts of a statusbar? (Winapi)

Good day,

I'm writing a GUI for my application in C++, using WinAPI. All working fine, I've got everything I need, including a parted statusbar, except for colorized parts.

My working GUI

I'm creating the statusbar like this:

int statwidths[] = {150, 350, 500, -1};

(...)

case WM_PAINT:
(...)
hStatus = CreateWindowEx(0, STATUSCLASSNAME, NULL, WS_CHILD | WS_VISIBLE, 0, 0, 0, 0, hwnd, (HMENU)IDC_MAIN_STATUS, GetModuleHandle(NULL), NULL);        
SendMessage(hStatus, SB_SETTEXT, 0, (LPARAM)"Item:");
SendMessage(hStatus, SB_SETTEXT, 1, (LPARAM)"Item:");
SendMessage(hStatus, SB_SETTEXT, 2, (LPARAM)"Setpoint:");
SendMessage(hStatus, SB_SETTEXT, 3, (LPARAM)"Status");

break;

Colorizing the whole thing is fairly easy:

SendMessage(hStatus, SB_SETBKCOLOR, 0, RGB(255,0,0));

..but that's not what I need. I want to be able to control the color of the individual parts. I've tried several methods, including this function, found on MSDN:

HWND DoCreateStatusBar(HWND hwndParent, int idStatus, HINSTANCE
                      hinst, int cParts)
{
    HWND hwndStatus;
    RECT rcClient;
    HLOCAL hloc;
    PINT paParts;
    int i, nWidth;

    // Ensure that the common control DLL is loaded.
    InitCommonControls();

    // Create the status bar.
    hwndStatus = CreateWindowEx(
        0,                       // no extended styles
        STATUSCLASSNAME,         // name of status bar class
        NULL,           // no text when first created
        SBARS_SIZEGRIP |         // includes a sizing grip
        WS_CHILD | WS_VISIBLE,   // creates a visible child window
        0, 0, 0, 0,              // ignores size and position
        hwndParent,              // handle to parent window
        (HMENU) idStatus,       // child window identifier
        hinst,                   // handle to application instance
        NULL);                   // no window creation data

    // Get the coordinates of the parent window's client area.
    GetClientRect(hwndParent, &rcClient);

    // Allocate an array for holding the right edge coordinates.
    hloc = LocalAlloc(LHND, sizeof(int) * cParts);
    paParts = (PINT) LocalLock(hloc);

    // Calculate the right edge coordinate for each part, and
    // copy the coordinates to the array.
    nWidth = rcClient.right / cParts;
    int rightEdge = nWidth;
    for (i = 0; i < cParts; i++) {
       paParts[i] = rightEdge;
       rightEdge += nWidth;
    }

    // Tell the status bar to create the window parts.
    SendMessage(hwndStatus, SB_SETPARTS, (WPARAM) cParts, (LPARAM)
               paParts);

    // Free the array, and return.
    LocalUnlock(hloc);
    LocalFree(hloc);
    return hwndStatus;
}

I was hoping to be able to play around with several colorized rectangles and get what I need via that way, not working. Tried to create parts via ownerdraw: SendMessage(hStatus1, SB_SETTEXT, 0 | SBT_OWNERDRAW, 0); , and deal with setting colors and backgrounds in the WM_DRAWITEM-case, same disappointing result: the statusbar is getting drawn but I'm not able to color it. I'm able to, for example, colorize the text in a pane with this code in my WM_DRAWITEM:

            lpDIS=(LPDRAWITEMSTRUCT)lParam;
            ptStr =(PTSTR)lpDIS->itemData;
            SetTextColor(lpDIS->hDC, RGB(0xFF, 00, 00));
            ExtTextOut(lpDIS->hDC, 0, 0, 0 , &lpDIS->rcItem,ptStr, strlen(ptStr), NULL);

which (weirdly) gives me this result

Tried playing around with bits and pieces that I use to color the background of the main GUI:

            HBRUSH brush;
            RECT rect;

            pen=CreatePen(PS_SOLID, 1, bkgndcolor);
            brush=CreateSolidBrush(bkgndcolor);
            SelectObject((HDC)wParam, pen);
            SelectObject((HDC)wParam, brush);

..but then I got stuck. GetClientRect(hwnd, &rect); Rectangle((HDC)wParam, rect.left, rect.top, rect.right, rect.bottom); obviously won't do the trick because "rect" contains the rectangle of the main window, and not the statusbar or a part of it.

Would someone be able to at least point me in the right direction? Searching this forum and the internet got me nowhere; apparently what I want is relatively rare. I cannot imagine it to be impossible though.

Thank you very much!

Upvotes: 0

Views: 828

Answers (1)

ZKJohan
ZKJohan

Reputation: 11

Thanks for the response, all. I managed to get it working with the following bits and pieces:

Filling my parts with SBT_OWNERDRAW in wParam. My windowprocessing looks like this:

(...)
        case WM_DRAWITEM:
            lpDIS=(LPDRAWITEMSTRUCT)lParam;
            GetClientRect((HWND)lpDIS->hwndItem, &rect);

            pen=CreatePen(PS_SOLID, 1, bkgndcolor);
            brush=CreateSolidBrush(bkgndcolor);
            SelectObject(lpDIS->hDC, pen);
            SelectObject(lpDIS->hDC, brush);

            Rectangle(lpDIS->hDC, rect.left, rect.top, rect.right, rect.bottom);

            ptStr =(PTSTR)lpDIS->itemData;
            SetTextColor(lpDIS->hDC, RGB(0,0,0));
            SetBkColor(lpDIS->hDC, bkgndcolor);
            SetBkMode( lpDIS->hDC, TRANSPARENT );
            DrawText(lpDIS->hDC, ptStr, -1, &rect, DT_VCENTER | DT_SINGLELINE);
        break;

I simply adjust the rect-struct (.left and .right) for every pane so that the rectangle covers it.

the result is pretty much what I wanted

Small remark is that the text is not nicely placed in the pane. I've tried writing the text with ExtTextOutA to give it an x- and y-offset but that only writes the string in the left-pane. DrawText seems to do the trick for writing in the proper rectangle. To give it some spacing, a quick fix would be to increase rect.left with two. A suggestion for a little less ugly workaround would be highly appreciated.

Another remark would be that the font seems to be different if I owner-draw it: see the screenshot, were #1 till #3 are owner-drawn. Not the biggest problem, but I think I like the "original" font more. Assuming that I have to select this font myself, would anybody happen to know what this font is and how big it needs to be to match the original?

Thanks all!

Upvotes: 1

Related Questions