July 30, 2014
Hot Topics:
RSS RSS feed Download our iPhone app

Create a Shaped 3D Control with GDI+

  • September 29, 2004
  • By Paul Kimmel
  • Send Email »
  • More Articles »

Implementing Control Methods

Listing 3: Custom control methods.

Imports System
Imports System.Collections
Imports System.ComponentModel
Imports System.Drawing
Imports System.Drawing.Drawing2D
Imports System.Data
Imports System.Windows.Forms

Public Class Cube3d
   Inherits System.Windows.Forms.Control

#Region " Component Designer generated code "

   Public Sub New()
      MyBase.New()

      SetStyle(ControlStyles.SupportsTransparentBackColor Or _
            ControlStyles.ResizeRedraw, True)

      InitializeComponent()

      FCube = New Cube(CubeX, CubeY, CubeHeight, CubeWidth, _
                       CubeDepth)

   End Sub
#End Region

   Private FPen As pen = New pen(Color.Black)
   Private FCube As Cube

   Protected Overrides Sub OnPaint(ByVal e _
      As System.Windows.Forms.PaintEventArgs)
      MyBase.OnPaint(e)
      Dim path As GraphicsPath = FCube.GetCube()
      e.Graphics.DrawPath(FPen, path)
      Me.Region = EnclosingRegion()
   End Sub

   Public Function EnclosingRegion() As Region
      Dim copy As Cube3D = Clone()
      copy.ScaleCube(1, 1, 1)
      Dim path As GraphicsPath = copy.Cube.GetCube()
      path.FillMode = FillMode.Winding
      Return New Region(path)
   End Function

   Public Function Clone() As Cube3d
      Dim copy As Cube3D = New Cube3d
      copy.SetCubeBounds(CubeX, CubeY, CubeWidth, CubeHeight, _
                         CubeDepth)
      Return copy
   End Function

   Public Sub ScaleCube(ByVal x As Integer, ByVal y As Integer, _
                        ByVal z As Integer)
      CubeLocation = New Point(CubeX - x, CubeY - y)
      CubeWidth += 2 * x
      CubeHeight += 2 * y
      CubeDepth += 2 * z
   End Sub

   Protected Overrides Sub OnResize(ByVal e As System.EventArgs)
      MyBase.OnResize(e)
      ResizeCubeStructure()
   End Sub

   Public Sub SetCubeBounds(ByVal x As Integer, _
      ByVal y As Integer, _ ByVal width As Integer, _
      ByVal height As Integer, ByVal depth As Integer)
      FCube.Location = New Point(x, y)
      FCube.Width = width
      FCube.Height = height
      FCube.Depth = depth
      Invalidate()
   End Sub

   Private Sub ResizeCubeStructure()
      FCube.FillRectangle(Bounds)
      Invalidate()
   End Sub
' elided intentionally!

The Listing 3 code modifies the constructor (Sub New) and OnPaint, and adds EnclosingRegion, Clone, ScaleCube, OnResize, SetCubeBounds, and ResizeCubeStructure. In the constructor, it adds a call to SetStyle. Passing an Or'd list of enumerated values permits you to customize the control style. For this demonstration, I elected to permit background transparency and enable automatic redrawing when the control is resized. The former permits see-through controls, and the latter ensures that the underlying cube representation adjusts when the control is resized.

For custom controls, the only method you really need to override is the OnPaint method. The OnPaint method is where you give a custom control its unique visual character. Your OnPaint method obtains the GraphicsPath—think array of points—that represents the cube, draws the cube, and then changes the control's region to match that of the cube shape rather than the rectangular control. (Refer to Shaping the Control for more information on using the Region property.)

The EnclosingRegion method plays a little game. Essentially, you obtain a copy of the cube and expand it three-dimensionally by one pixel, providing enough room for the cube outline. You use a copy because you don't want to change the cube itself; you just want a little more room for the clip region—visible area—of the cube. The Clone method creates a new instance, a copy, of the cube itself.

ScaleCube accepts three points and adjusts the location, width, height, and depth. (Multiplying width and height by 2 accounts for the offsetting change to x and y.) As well as permitting the cube to shrink and swell, you use this method to permit enough room to ensure that the cube control's outline is visible along the edges. (Scaling the cube to make room for the visual image is a bit dodgy, as my friend Tony Cowan would say, and could stand some improvement.)

The OnResize method is overridden to ensure that when the control is resized the underlying cube is resized relatively. Without this method, the actual dimensions of the cube could be greater or less than the size of the control, breaking the illusion of the control conforming to the primitive's dimensions.

Finally, SetCubeBounds accounts for the depth dimension and invalidates the control, so that it is redrawn, and ResizeCubeStructure shrinks or grows the cube to fit the control's bounds and again causes the control to be redrawn.

Surfacing Constituent Properties

The 3D cube control is defined by a location and three Cartesian points representing height, width, and depth. While it makes sense to permit the consumer to modify the location and dimensions, permitting design-time modification of other properties probably makes no sense and may be error prone. Listing 4 contains only the properties that you will permit consumers to modify at design time. Simply add the code in Listing 4 to the Cube3D's class code. (The complete Listing is provided in Control Code Listing.)

Listing 4: The public, design-time modifiable properties of the 3D Cube control.

   Public Property CubeWidth() As Integer
      Get
         Return FCube.Width
      End Get
        Set(ByVal Value As Integer)
         FCube.Width = Value
         Invalidate()
      End Set
   End Property
   Public Property CubeHeight() As Integer
      Get
         Return FCube.Height
      End Get
      Set(ByVal Value As Integer)
         FCube.Height = Value
         Invalidate()
      End Set
   End Property
   Public Property CubeDepth() As Integer
      Get
         Return FCube.Depth
      End Get
      Set(ByVal Value As Integer)
         FCube.Depth = Value
         Invalidate()
      End Set
   End Property
   Public Property CubeCenter() As Point
      Get
         Return FCube.Center
      End Get
      Set(ByVal Value As Point)
         FCube.Center = Value
         Invalidate()
      End Set
   End Property
   Public Property CubeLocation() As Point
      Get
         Return FCube.Location
      End Get
      Set(ByVal Value As Point)
         FCube.Location = Value
         Invalidate()
      End Set
   End Property

If you want to change all of the cube's dimensions, call SetCubeBounds. Each of the cube's location and dimensional properties individually causes the cube to be redrawn. These properties, modifiable at design time, are CubeWidth, CubeHeight, CubeDepth, CubeCenter, and CubeLocation. CubeLocation moves the upper-left corner of the cube, and CubeCenter relocates the cube relative to its three-dimensional center. Each of these properties is implemented in terms of the underlying 3D cube structure.





Page 2 of 6



Comment and Contribute

 


(Maximum characters: 1200). You have characters left.

 

 


Sitemap | Contact Us

Rocket Fuel