4

We're writing Windows desktop apps using C++ and Win32. Our dialog boxes have an ugly appearance with "Windows XP style": the background to the static text is grey. Where the dialog box background is also grey, this is not a problem, but inside a tab control, where the background is white, the grey background to the text is very noticeable.

In the past we have done a lot of our own drawing of controls, but these days we are trying to use the standard look'n'feel as much as possible, and to avoid overriding standard behaviour as much as possible.

We are using the Win32 API, which is getting a bit dated, but I think the problem occurs even with ATL. We are creating a DIALOGTEMPLATE. The text is in a "static" control (0x0082). The only flag we set for the style is "SS_LEFT". The text control is inside a tab control: "SysTabControl32" with only one flag: WS_CLIPSIBLINGS set on it. I've experimented with SS_WHITERECT and WS_EX_TRANSPARENT and other settings, to no avail.

All of this gets drawn with the standard Windows dialog box message handler. My main question is "what are we doing wrong?" rather than "how can I work around it?", although I'll settle for the latter if no-one can help me with the first.

Any ideas?

Tim Cooper
  • 10,023
  • 5
  • 61
  • 77
  • Out of interest are you using a manifest file for the XP theme look and feel? – Rob Jun 25 '09 at 06:56
  • yes we are: #pragma comment(linker, "/manifestdependency:\"type='win32' " \ "name='Microsoft.Windows.Common-Controls' " \ "version='6.0.0.0' " \ "processorArchitecture='*' " \ "publicKeyToken='6595b64144ccf1df' " \ "language='*'\"") – Tim Cooper Jul 01 '09 at 01:45

6 Answers6

6

The usual way of implementing pages in a tab control is required to access MS's solution to this problem :-

Instead of creating individual controls in the tab area, create a modeless child dialog for each page and have the controls on that. Create the page dialogs with the main dialog (not the tab) as their parent and as the user switches between tabs, simply show and hide the relevant page dialog.

In the WM_INITDIALOG handler for each page, call the uxtheme API EnableThemeDialogTexture

With the ETDT_ENABLETAB flag this automatically changes the background color of the dialog and all its child controls to paint appropriately on a tab.

If you have overridden WM_ERASEBKGND or WM_CTLCOLOR* in your pages DialogProc you will need to revert to default handling (return FALSE) as these methods are where the dialog code is going to do its heavy lifting. The style bits should simply be set as though the child page dialog page was going to be created on a normal windows 9X tabbed dialog.

Marco A.
  • 43,032
  • 26
  • 132
  • 246
Chris Becke
  • 34,244
  • 12
  • 79
  • 148
  • Are you saying that using the tab control of the "Common controls" Microsoft library (ICC_TAB_CLASSES, TabCtrl_SetCurSel) is not the "usual way" of implementing pages in a tab control? What you're suggesting sounds like a lot of work ("create a modeless child dialog for each page"). – Tim Cooper May 30 '11 at 01:52
  • 1
    To simplify the complexity of tab controls, there is the Property Sheet API. The property sheet api implements tabbed property pages as Ive described: Each property sheet page is provided as a separate dialog. The ICC_TAB_CLASSES class is used to draw (and manage) the tab area of the tab control, but the content area is managed by the parent dialog responding to notification messages from the tab control by hiding and showing the relevant child dialog. – Chris Becke May 30 '11 at 07:21
4

The reason why the background is gray is because that is the default.

To override it, you can process the WM_CTLCOLORSTATIC message in the parent window and return a custom brush.

StackedCrooked
  • 34,653
  • 44
  • 154
  • 278
  • Grey is _not_ the default for the contents of a tab control with the XP style. – Tim Cooper Jun 30 '09 at 21:46
  • 1
    @Tim: you're missing the point. Gray is the default for *static controls*. – Hans Passant Oct 17 '10 at 12:46
  • @Hans: I realise that. We're using the default colours for all controls, but the problem is that this looks weird because white is the default background for tab controls but grey is the default background for static controls. So we get a patchwork background. – Tim Cooper May 30 '11 at 01:45
1

Your problem is not with ATL or WinAPI. In MFC there is the same problem. Set Tab control as parent window for Static controls. But I think that overriding WM_DRAWITEM is more flexible solution.

Kirill V. Lyadvinsky
  • 97,037
  • 24
  • 136
  • 212
0

I've got Win32/MFC applications with labels inside tabs on dialogs, and the background colour looks fine on them (that is, it reflects the XP-look theme, rather than being flat grey) without any obvious special handling.

Under the hood what's supposed to happen is that the label posts a WM_CTLCOLOR message to its parent, which sets the device context up appropriately: the default handling in Windows should set the appropriate background colour, at least for dialogs and tab controls.

One possibility is that you're doing something non-standard in your handling of WM_CTLCOLOR: is it over-ridden somewhere in your application? Possibly you have some old code that is setting the label background colour in this way.

(Also, as Rob asks, are you using a manifest to get comctl32 6.0 into your application?)

DavidK
  • 3,929
  • 1
  • 19
  • 26
0

We're not overriding the WM_CTLCOLORSTATIC message. There's no occurrence of this string in our source code and nothing like it in our message handlers.

We've worked around this problem by overriding the WM_DRAWITEM message for tab controls to paint their contents with the grey background (standard for dialog boxes without tab controls) rather than the white background (standard for the contents of tab controls).

        brush = CreateSolidBrush(GetSysColor(COLOR_MENU));
        FillRect(lpdis->hDC, &lpdis->rcItem, brush);
        SetBkColor(lpdis->hDC, GetSysColor(COLOR_MENU));
        wtext = ToWideStrdup(c->u.tabcontrol.Tabs[lpdis->itemID].name);
        rect = lpdis->rcItem;
        rect.top += DlgMarginY - 1;
        rect.bottom += DlgMarginY;
        DrawTextW(lpdis->hDC, wtext, -1, &rect, DT_CENTER | DT_VCENTER);
        free(wtext);
        DeleteObject(brush);

This is obviously a workaround, not a proper answer to my question.

Incidentally, we initialise the "common controls", of which I believe the tab control is one, using code like this...I don't suppose this is related to the issue?

#pragma comment(linker, "/manifestdependency:\"type='win32' " \
    "name='Microsoft.Windows.Common-Controls' " \
    "version='6.0.0.0' " \
    "processorArchitecture='*' " \
    "publicKeyToken='6595b64144ccf1df' " \
    "language='*'\"")
...

hCommCtrl = GetModuleHandle("comctl32.dll");`
if (hCommCtrl) {
        ptrInit = (TfcInit_fn) GetProcAddress(hCommCtrl, "InitCommonControlsEx");
        if (ptrInit) {
            data.dwSize = sizeof(INITCOMMONCONTROLSEX);
            data.dwICC  = ctrlClass;
            if (ptrInit(&data) )
                gCommCtrlsInitialized |= ICC_TAB_CLASSES | ICC_BAR_CLASSES;
        }
}
Tim Cooper
  • 10,023
  • 5
  • 61
  • 77
0

Have spent an amazing amount of time to try to fix a problem so seemingly simple, tried almost every constant for hbrBackground without success.

As an amateur found that the most simple & time efficient fix was to simply create a "Static" class child window that envelops the entire window. Just another hack level fix though