The 3-D Feel


Windows 95 and Windows NT version 4 have a 3-D feel throughout. Buttons and windows with squared corners give a more sharply defined effect than the rounded corners of previous versions.


The three-dimensional effect is easy to achieve by setting the Appearance property to 3D (the default). You can provide the same feel at a lower level using Win32 draw functions. We’ll talk briefly about two of these, DrawEdge and DrawFrameControl.


DrawEdge creates the low-level 3-D effects that the system uses to draw 3-D buttons and other controls. You can also use it to draw your own controls. Imagine writing your own Button control that does everything CommandButton does, and more. The Test Edges program (in TEDGE.VBP) demonstrates the techniques you might use in such a control. You can play with the check boxes to see which flags give different effects. Some combinations aren’t meaningful, but you can experiment until you find the ones you like. Figure 11-8 shows some of the more common effects. For a surprising effect, click the Adjust check box repeatedly.



Figure 11-8. Drawing edges and controls.


The fake CommandButton in the example is actually the following RECT ­variable:

Private cmd As RECT

Here’s the code that initializes and draws the button:

With lblButton
cmd.Left = .Left
cmd.Top = .Top
cmd.Right = .Left + .Width
cmd.bottom = .Top + .Height
End With
InitButton

The RECT variable is used to draw the button edges over a transparent label containing the button text. This makes it easy to size the rectangle and to ­respond to clicks on the label as if they were on the button. In this sample, the ScaleMode of the form is set to vbPixel so that RECT values can be assigned directly. If your programs need to use a different ScaleMode (such as the default twips), you’ll need to convert control coordinates to pixel values for RECT variables.


The InitButton procedure sets up the initial check box states and calls Update­Button. UpdateButton initializes flags based on the check box settings and then draws the button using the following statement:

DrawEdge hDC, cmd, afBorder, afStyle

The afBorder and afStyle variables are bit flags corresponding to the check boxes on the sample form.


The DrawFrameControl function works at a higher level than DrawEdge. This function can draw different kinds of predefined buttons and other controls such as the Cool CheckBox control and the Change and Reset OptionButton controls shown in Figure 11-8. You pass flags that describe the type and the state of the control. Like the button control shown earlier, the fake button is drawn on top of a transparent label so that the label can respond to mouse events. Here’s how the Click event of the label calls DrawFrameControl to toggle the check box:

Private Sub lblBigCheck_Click()
If afChk <> (DFCS_BUTTONCHECK Or DFCS_CHECKED) Then
afChk = DFCS_BUTTONCHECK Or DFCS_CHECKED
Else
afChk = DFCS_BUTTONCHECK
End If
DrawFrameControl hDC, chk, DFC_BUTTON, afChk
End Sub

The checkbox and the option buttons shown in the example are just two of the many common elements you can draw with DrawFrameControl. See the Win32 documentation for more details. If you like DrawEdge and DrawFrameControl, check out the other new draw functions: DrawAnimatedRects, DrawCaption, DrawState, DrawStatusText, and DrawTextEx.


The built-in controls make DrawEdge and DrawFrameControl unnecessary in most cases, but I can think of a few situations where they might be useful. First you could make a set of ActiveX controls that encapsulate check boxes and option buttons with user-defined sizes. Before you spend a lot of time on this, try exploring the new DisabledPicture, DownPicture, Picture, Mask­Color, UseMaskColor, and Style properties of the CheckBox and OptionButton controls. You might be able to get the effect you want (or an even better effect you never considered) without DrawFrameControl. The DrawEdge function can be used to get around an annoying limitation when delegating ActiveX controls. You’ll find that you can’t delegate the Appearance property because it is (for no good reason) read-only at run time. You could, however, implement your own Appearance property with Draw­Edge. In fact, you could give your better Appearance property more settings. Instead of limiting users to Flat and 3D, you could offer Flat, Raised, Sunken, and Etched.