The XPictureGlass Control


If you were confused by the code for the CPictureGlass class, you’ll like the control version. It requires only four lines of code. Of course, any control requires a lot more than four lines of code, but I’m counting only the ones you have to write yourself. The ActiveX Control Interface Wizard generated the rest.


Although controls are a major feature of Visual Basic version 5, this is the first I’ve had to say about creating them. I’ll have more to say about controls in Chapter 9, but I won’t be doing much hand-holding. The documentation on creating controls is good, and I assume you’ll use it. I’ll only get into a few quirks related to specific tasks I want to accomplish. So here’s a brief outline of how I created XPictureGlass.
  1. Asked the ActiveX Control Interface Wizard to generate a control that had the same properties, methods, and events as a PictureBox. I didn’t delegate to an internal PictureBox; I emulated a new one. I instructed the wizard to delegate all the emulated members to the UserControl. Had I stopped there, I would have had essentially a PictureBox control. If you assign a picture to the Picture property, it appears on the surface of the UserControl just as it would on a normal PictureBox.

  2. Gave the control a MaskColor property (but not a MaskPicture
    property).

  3. Changed the BackStyle property of the UserControl to Transparent (0) at design time.

  4. Did a few minor fixups that the wizard can’t handle such as changing color properties to type OLE_COLOR and using standard enums for properties that need drop-down enumerations. These tasks are documented in manuals and in the wizard’s summary report (CTLWIZ.TXT).

  5. Added the following lines of code:
Public Property Set Picture(ByVal New_Picture As Picture)
Set UserControl.Picture = New_Picture
‘ Begin new code
Set UserControl.MaskPicture = New_Picture
If Not New_Picture Is Nothing Then
UserControl.Width = New_Picture.Width
UserControl.Height = New_Picture.Height
End If
‘ End new code
PropertyChanged “Picture”
End Property

That’s it.


So why did I go through all that rigamarole with CPictureGlass? Well, XPic­tureGlass exists at a much higher level than CPictureGlass. The developers of Visual Basic gave UserControl the MaskColor and MaskPicture properties at the last minute (they’re documented in the README). You set the MaskColor that you want masked out and the MaskPicture to the picture you want to mask. In this case, the Picture property and the MaskPicture property get the same value. Then behind the scenes—with some sort of magic not entirely different than what you saw in CPictureGlass—they make a mask from the MaskPicture and MaskColor and blit it onto the UserControl surface.


But they do a lot more…. For example, they do events. If you click on a transparent pixel of the control (one that has the MaskColor), you don’t get a mouse click event. If you click on an opaque bit, you do. In order to make transparency so easy, the Visual Basic designers had to make high-level decisions about how to work with AutoRedraw and ClipControls properties on the container. The decisions they made will probably work better for you than they did for the Fun ’n Games program.


When you animate the picture, it saves and restores the background, whatever it is. When you animate the control, it respects controls on the form but wipes out anything it interacts with on the form background. The control is designed to be transparent on the bitmap surface that you saved for the form when you set AutoRedraw to True. Furthermore, it doesn’t understand the trick (see “Style bits,” page 310) used to turn off ClipControls at run time. A partial solution is to set AutoRedraw to True and call the control’s Refresh method in the form’s Paint event. The problem with that is that none of the other fun effects works as well with AutoRedraw set to True. Never mind. Fun ’n Games is just a demo, and, as noted earlier, real programs will need a more sophisticated painting strategy.