MFC: как визуализировать поле со списком в стиле Aero для рисования владельцем?

Я унаследовал большое приложение MFC, которое содержит подкласс CComboBox, который переопределяет OnPaint. В настоящее время он рисует все вручную (с помощью линий и прямоугольников) и отображает поле со списком, которое явно выглядит в стиле Windows 98. Однако в остальном он отлично работает и предоставляет множество полезных настраиваемых функций, на которые мы полагаемся, и переписывание всего элемента управления, вероятно, не вариант.

Я хотел бы модернизировать его, чтобы OnPaint рисовал в стиле Aero там, где это возможно (возврат к старому коду, когда современные темы недоступны). Я сделал это с некоторыми другими настраиваемыми элементами управления, которые у нас есть, например с кнопками, и это отлично подходит для наших целей. Я знаю, что есть некоторые крохотные особенности, с которыми он не справится, например, мягкие блики при наведении курсора мыши, но это не имеет большого значения для этого приложения.

У меня есть доступ к CVisualStylesXP ckass, так что у меня уже есть инфраструктура, позволяющая легко выполнять такие вызовы, как OpenThemeData, GetThemeColor или DrawThemeBackground (через LoadLibrary, поэтому мы не используем Vista как min-систему). К сожалению, я не знаю правильной последовательности вызовов для получения красивого поля со списком с соответствующей теме рамкой и кнопкой раскрывающегося списка.

Кто-нибудь знает, что здесь делать?


person StilesCrisis    schedule 15.03.2012    source источник


Ответы (3)


Честно говоря, я не знаю, почему они изначально пытались переопределить OnPaint. Есть ли на то веская причина? Я думаю, что по крайней мере в 99% случаев вы просто захотите переопределить отрисовку элементов в ComboBox. Для этого вы можете переопределить DrawItem, MeasureItem и CompareItem в производном поле со списком, чтобы получить желаемую функциональность. В этом случае ОС будет правильно рисовать непользовательский контент, специфичный для каждой ОС.

person Joseph Willcoxson    schedule 15.03.2012
comment
Честно говоря, да, это в основном выглядит как обычное поле со списком, кроме текста, отображаемого в середине. Но я действительно не хочу его переделывать. - person StilesCrisis; 16.03.2012
comment
На самом деле, если задуматься, это делает дроплист больше похожим на раскрывающийся список (он в основном позволяет пользователю вводить любое подмножество текста, а затем в списке отображаются отфильтрованные результаты). Было бы неправильно рисовать просто как дроплист. - person StilesCrisis; 17.03.2012

Думаю, вам лучше всего не углубляться в тематику xp и различные системные показатели, взглянув на этот проект: http://www.codeproject.com/Articles/2584/AdvComboBox-Version-2-1

Проверьте OnPaint класса CAdvComboBox - есть полная реализация перерисовки элемента управления, включая проблемы, связанные с темой xp.

person sigman    schedule 24.03.2012
comment
К сожалению, я уже пробовал это, и он не похож на поле со списком Aero. Мне кажется, что они взломали его и сделали обоснованные предположения, пока внешний вид не соответствовал тому, что сделал XP, но это совершенно неправильно для Aero. Например, кнопка со стрелкой на правом краю заключена в квадратную кнопку, что подходит для Luna, но не для Aero. - person StilesCrisis; 24.03.2012
comment
Ой, как плохо. Хорошо, есть еще один, который может быть немного сложнее удалить соответствующий код, но лучше работает в стиле аэро. codeproject.com/Articles/130682/ Соответствующий код находится в файле VComboBox.cpp - person sigman; 24.03.2012

Не уверен, что это такая же ситуация, но когда я столкнулся с этой проблемой (в моем случае с подклассами CButtons), для ее решения потребовалось только изменить объявление элемента управления на указатель и создать элемент управления динамически.

Предположим, что ваш подклассовый элемент управления называется CComboBoxExt.
Где у вас был

CComboBoxExt m_cComboBoxExt;

Теперь у вас будет

CComboBoxExt* m_pcComboBoxExt; 

И в OnInitDialog окна, в котором размещен элемент управления, вы создаете его, используя

m_pcComboBoxExt = new CComboBoxExt();  
m_pcComboBoxExt->Create(...)

Поскольку теперь это указатель, не забудьте вызвать DestroyWindow() и удалить указатель при завершении.

Это решило мою конкретную проблему - если ваш элемент управления объявлен таким же образом, подумайте о том, чтобы попробовать.

person baderous    schedule 14.04.2012
comment
Это не исправит мою OnPaint, которая вручную рисует линии и заполняет поля. - person StilesCrisis; 14.04.2012