November 29, 2002

XP Visual Styles

Ah, I feel a rant coming on. How many hours must I spend fighting with CommCtrls 6 just to get my app to look right under XP.

To start lets go for ownerdraw buttons. The second you ask for ownerdraw (or bitmap buttons for that matter) XP decides that you couldn't possibly want the themed background for your button. I had to find the code to do the entire drawing process myself. Wonderful.

Continuing on the theme (pun not intended) of buttons, try creating a simple application with a number of buttons on a dialog. Enable theming for this application and keep running the app. Try moving the focus between buttons by clicking on each different one, and then separately try using the keyboard to move between them. If you can describe the rules that define the difference between these two drawing styles (below) then please do let me know:

And now to tab controls. These can look really nice when properly themed. The only problem is that it seems nigh-on impossible to get this right.

Scenario 1: Create a tab control on a dialog, and use dialogs for the pages. The tab control will appear correctly themed, but the dialogs (the tab pages) will not. Use EnableThemeDialogTexture I hear you cry. Unfortunately, while this might appear to work at first you'll notice two things:

1) The background of the tab page does not contain the correct gradiented background, but simply a plain colour all over. wrong.

2) Try adding a checkbox to the dialog. Oh dear, it would appear that the checkbox is drawing the old grey colour instead of the nice white that should be used. disaster!

I tried a number of different ways to solve this problem including overriding WM_ERASEBKGND, WM_CTLCOLORDLG, WM_CTLCOLORSTATIC and friends. None of these could get the correct gradient in the background of the tab.

Scenario 2: At this point, I noticed that property pages seemed to look OK in some programs that I'd seen, so I decided to try swapping my tab control for a property sheet and see if that works.

Low and behold, my first tab looked fantastic - all the controls were correctly themed, the checkboxes had transparent backgrounds and the tab had a gradient. Who knows what's different between a property sheet and a tab control.

Then I switched to my second tab page (which had only a list control on it). disaster! The second page had the all-original, everyone's favorite COLOR_BTNFACE background. So why did one page work, and the other not? To cut a long story short (one which involved lots of resource editing and recompiling) I discovered that page one had a button control on it, and page two didn't. Adding a single button to page two enabled the theming. Please, someone, explain this madness to me!

If anyone has a surefire way to enable theming on XP tab controls, then please let me know. I would be most grateful for your help.

Posted by Simon at November 29, 2002 05:28 PM
Feedback

You don't really need to override or ownerdraw anything. All you need to do is add the manifest file and make sure that the controls have their FlatStyle property set to FlatStyle.System. You can get the correct manifest file from GotDotNet.

http://www.gotdotnet.com/team/windowsforms/Themes.aspx

Posted by sean at Nov 30, 2002 1:51 AM

Ah, I should have mentioned that this is when using C++ with either WTL or MFC. I wish it was so easy with those! I do have a manifest file, but that doesn't make every control work unfortunately.

Thanks for the hint, I'll remember it when next using .NET.

Posted by simon at Nov 30, 2002 11:05 AM

Help! I was looking for the toilets and seem to have wanderd in here by acident. Does anybody know the way out?

Posted by Duncan at Dec 2, 2002 9:25 AM

OMFG simon!!! im having the same problem and everywhere I look people are using these crappy languages like vb and c# where they got there nice little flatstyle.system property, and when I ask this SAME QUESTION they say "oh thats easy dumbass, just set the flatstyle property" and I have to respond "THATS NICE JACKASS BUT I STOPPED PLAYING WITH LEGOS 10 YEARS AGO, START USING A REAL LANGUAGE AND THEN COME TALK TO ME" AHHHHH well I kinda got this stuff to work by returning a NULL_BRUSH in response to the WM_PAINT message, but alas that doesn't work nearly as well as u have gotten your project to work, could I perhaps see ure source for getting checkboxes to work??? everytime I try checkboxes they turn completely black, wtf!?!?! please email me instead of posting here =)

Posted by Bubba at Jan 6, 2003 12:40 AM

OMG, i told u wrong I return a NULL_BRUSH in response to the WM_CTLCOLORDLG/WM_CTLCOLORSTATIC messages. But still this doesn't really fix the problem

Posted by Bubba at Jan 6, 2003 12:50 AM

Ok, i tried that property sheet thing and everything is workin for me now... I dont have to add a button to a property sheet to display correctly but I do have to add at least 1 control for it to work. BUT this still sucks because a property sheet is 1000000 times harder to customize than a regular tab control !!! I dont want Ok, Cancel, Apply buttons ! I dont want a help button on the title bar ! I want a minimize button instead, a taskbar entry would be nice too. Im sure I could accomplish all of this but it would be a lot harder to do than just simply having a tab control in my resource file...

Posted by Bubba at Jan 6, 2003 3:33 AM

ok i lied... if i just put a list control on a tab page i also get bad results... but this is easily fixed with the NULL_BRUSH / WM_CTLCOLORSTATIC solution

Posted by Bubba at Jan 7, 2003 3:30 AM

Having the same problem here too ... really fucked up! NULL_BRUSH works almost for me ... there is just 1 little problem ... the static controls (text, groupbox, checkbox and radiobox) give a white background ... and if I skip the WM_CTLCOLORSTATIC part, it becomes GRAY :-/ ... so there is another color message ... somewhere ...
I'm doing this for the Dialog now:

Posted by B at Jan 24, 2003 12:15 PM

NULL_PEN worked for me.

Posted by William at Nov 5, 2003 9:44 AM

Hey Bubba,
How come you don't like .Net

If you really like C++ it is integrated in .Net now and you get the FlatStyle property on buttons and full XP Theme support.

this->button1->FlatStyle = System::Windows::Forms::FlatStyle::System;

Use languages for what they are designed for, not just from personal preference.

Posted by The voice of common sense at Jun 30, 2004 10:31 AM