Стиль 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 в ваше приложение?)