Reputation: 11
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.
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
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