Стиль Windows XP: Почему мы получаем темно-серый фон для статических текстовых виджетов?

Мы пишем настольные приложения для Windows, используя C++ и Win32. Наши диалоговые окна выглядят ужасно с "стилем Windows XP": фон статического текста серый. Там, где фон диалогового окна также серый, это не проблема, но внутри элемента управления вкладками, где фон белый, серый фон текста очень заметен.

В прошлом мы много рисовали для элементов управления, но в наши дни мы стараемся максимально использовать стандартный look'n'feel и максимально избегать стандартного поведения.

Мы используем Win32 API, который немного устарел, но я думаю, что проблема возникает даже с ATL. Мы создаем DIALOGTEMPLATE. Текст находится в "статическом" элементе управления (0x0082). Единственный флаг, который мы устанавливаем для стиля, это "SS_LEFT". Текстовый элемент управления находится внутри элемента управления вкладкой: "SysTabControl32", для которого установлен только один флаг: WS_CLIPSIBLINGS. Я экспериментировал с SS_WHITERECT и WS_EX_TRANSPARENT и другими настройками, но безрезультатно.

Все это рисуется с помощью стандартного обработчика сообщений диалогового окна Windows. Мой главный вопрос "что мы делаем не так?" а не "как я могу обойти это?", хотя я согласен на последнее, если никто не может помочь мне с первым.

Есть идеи?

6 ответов

Решение

Мы не переопределяем сообщение WM_CTLCOLORSTATIC. В нашем исходном коде нет этой строки и ничего подобного в наших обработчиках сообщений.

Мы решили эту проблему, переопределив сообщение WM_DRAWITEM для элементов управления вкладками, чтобы закрасить их содержимое серым фоном (стандартно для диалоговых окон без элементов управления вкладками), а не белым фоном (стандартно для содержимого элементов управления вкладками).

        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);

Это явно обходной путь, а не правильный ответ на мой вопрос.

Между прочим, мы инициализируем "общие элементы управления", из которых я считаю, что вкладка является единым элементом управления, используя такой код... Не думаю, что это связано с проблемой?

#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;
        }
}

Обычный способ реализации страниц в элементе управления вкладками необходим для доступа к решению MS этой проблемы:

Вместо того, чтобы создавать отдельные элементы управления в области вкладок, создайте немодальный дочерний диалог для каждой страницы и поместите элементы управления на это. Создайте диалоги страницы с основным диалогом (не вкладкой) в качестве родительского элемента, а пользователь переключается между вкладками, просто показывает и скрывает соответствующий диалог страницы.

в WM_INITDIALOG обработчик для каждой страницы, вызовите uxtheme API EnableThemeDialogTexture

С ETDT_ENABLETAB Отметьте, что это автоматически изменяет цвет фона диалога и всех его дочерних элементов управления, чтобы рисовать соответствующим образом на вкладке.

Если вы переопределили WM_ERASEBKGND или же WM_CTLCOLOR* на ваших страницах DialogProc вам нужно будет вернуться к обработке по умолчанию (вернуть FALSE), так как эти методы - то, где код диалога будет выполнять свою тяжелую работу. Биты стиля должны быть просто установлены, как если бы диалоговая страница дочерней страницы создавалась в обычном диалоговом окне с вкладками Windows 9X.

Причина, по которой фон имеет серый цвет, заключается в том, что это значение по умолчанию.

Чтобы переопределить его, вы можете обработать сообщение WM_CTLCOLORSTATIC в родительском окне и вернуть собственную кисть.

Ваша проблема не с ATL или WinAPI. В MFC такая же проблема. Установите элемент управления Tab в качестве родительского окна для статических элементов управления. Но я думаю, что переопределение WM_DRAWITEM это более гибкое решение.

Потратили невероятное количество времени, чтобы попытаться решить проблему, настолько простую, на первый взгляд, безуспешно пробовали почти все константы для hbrBackground.

Любитель обнаружил, что самым простым и эффективным по времени решением было просто создать дочернее окно класса "Static", которое охватывает все окно. Просто еще одно исправление уровня взлома

У меня есть Win32/MFC-приложения с метками внутри вкладок в диалогах, и цвет фона на них выглядит хорошо (то есть отражает тему в стиле XP, а не просто серый) без какой-либо очевидной специальной обработки.

Под капотом должно происходить то, что метка отправляет сообщение WM_CTLCOLOR своему родителю, что соответствующим образом устанавливает контекст устройства: обработка по умолчанию в Windows должна устанавливать соответствующий цвет фона, по крайней мере для диалогов и элементов управления вкладками.

Одна из возможностей заключается в том, что вы делаете что-то нестандартное в обработке WM_CTLCOLOR: переопределено ли это где-то в вашем приложении? Возможно, у вас есть какой-то старый код, который устанавливает цвет фона метки таким образом.

(Кроме того, как спрашивает Роб, вы используете манифест для добавления comctl32 6.0 в ваше приложение?)

Другие вопросы по тегам