|
|||||||||||||||||||||||
|
|||||||||||||||||||||||
|
Announcements
Chapters
Services
Feature Zones
|
IntroductionI was surprised to find that Visual Studio 2003 .NET, the latest and greatest Windows application development tool, doesn't include an easy way to create XP-style buttons. Then I noticed that Office XP mostly uses the old-fashioned 3D buttons, suggesting that implementing the new style is not trivial. The new buttons are mostly found in Windows XP accessories and Internet Explorer 6. As a programmer, my first reaction was to jump in and reinvent the wheel, which reminds me that I need to start waiting for my second reaction before I waste any more time. This article describes a way to create XP-like buttons by implementing the button's Paint method. It's an (interesting, I hope) exploration of GDI+ graphics. But you don't have to go to all this trouble, nor do you have to accept less than perfect results, to achieve XP buttons. You simply need to link your Windows Form application with the latest version (6.0) of ComCtl32. The Real Way to Get XP ButtonsThe way to get XP-style controls in your VB.NET application is to create a manifest file that accompanies your .exe file. The manifest specifies that your code depends upon ComCtl32.DLL. A manifest file is like a config file--it's XML and it has the same name as your app, but with ".manifest" appended. If your app is MyApp.exe, then you need to create MyApp.exe.manifest in the same directory. <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
This information comes from an (apparently) old article (from when XP was called
Whistler) called How
to be ready for Windows XP's updated visuals, and from poking around the
system. The only other magic you need is to set the BackgroundHaving decided that I would have to subclass Button somehow and intercept
I expected several things that were not true as it turned out. First, I thought
that I would need to inform the button that it would be owner-drawn. Not so--apparently,
the existence of a method that "Handles Button1.Paint" sets a private "owner-draw"
field in the button to True. Second, I thought that my Paint handler would be
called with explicit "state" instructions--inactive, focus, hover, pressed,
and so on (like an owner-draw Tab control gets Implementing the button shown here was not particularly difficult, thanks to GDI+ methods that now include gradient brushes and graphics paths. There is considerable room for improvement, and I welcome any and all comments or suggestions. The 2D drawing primitives can be further optimized, perhaps. I tried to use system colors as an attempt to be "theme-aware" but there are probably better ways to do that, too. In general, I didn't sweat the details too much--my pressed button indents more than the standard Windows XP button, for instance. Using the codeTo use this code in your application, paste the code (exclusive of the Form Designer generated code)
into your form and add " That is, instead of: Private Sub PaintXPButton(ByVal sender As Object, _
ByVal e As System.Windows.Forms.PaintEventArgs) _
Handles Button1.Paint
To style your Private Sub PaintXPButton(ByVal sender As Object, _
ByVal e As System.Windows.Forms.PaintEventArgs) _
Handles btnOK.Paint, btnCancel.Paint
It's important that you change each button's This code illustrates one set of visual behaviors, but hopefully it will inspire others to try more imaginative effects. There are only four states that matter to me--normal, pressed, hot (mouse over), and disabled, but your application may need more. The gradient makes the normal button appear somewhat convex. When the button is pressed, I change it to concave by inverting the gradient and adding a highlight rectangle. This is more exaggerated than the official XP button's behavior. When the mouse is over the normal button (or the mouse has left the pressed button), I draw an orange rectangle as a nod toward what XP does. It's more of a "glow" effect, really, so I draw extra highlight lines around the rectangle. I think orange was chosen because it shows up against most background colors. Since there is no orange in the system color palette, I assume that XP always uses orange, so I do, too. Known BugsThis code ignores focus. The focus rect is never drawn. I don't miss it, but if you want to implement the focus rect, you'll have to figure out how to determine when the button has the focus and when it doesn't. Drawing the rect probably involves a hatched brush, but that's as much as I want to contemplate. Likewise, the code ignores the button's
I notice that the code assumes that the button's Form is its parent. If you are styling buttons in
other containers (such as a Points of InterestRound-cornered rectangles have disappeared, it seems, which is somewhat troublesome when the button
you're trying to draw has eased corners. The new And another thing: I'm slightly embarrassed to say that converting the mouse position to button
coordinates stumped me for several minutes. I looked for ButtonContainer.PointToClient(mousePos)
'ButtonContainer might be the form (Me), or it might not
Jan Tielens' article, A simple XP/VS.NET style button control, may be of interest, as well, as he describes a method for dimming and brightening buttons--more prods toward imaginative visual behaviors. History
|
||||||||||||||||||||||