The IconButton Control

function OpenWin(url, w, h) { if(!w) w = 400; if(!h) h = 300; window.open(url, "_new", "width=" + w + ",height=" + h + ",menubar=no,toobar=no,scrollbars=yes", true); }

The IconButton Control

Okay, time for something interesting. With the basics covered, it's time to dive in and create a simple control based on the information provided so far. The example we'll use creates a custom pushbutton that displays an icon to the left of the text. In addition to providing the C# implementation, the IconButton has also been implemented in VB .NET to show that it is possible to create the same types of controls regardless of language choice.

Choosing the base class for a custom control requires evaluating the functionality needed by the control. Because the IconButton control doesn't scroll and is not going to host other controls, the System.Windows.Forms.Control base class provides all the required functionality needed to serve as a starting point from which to build. Figure 2.6 shows the IconButton being used in an application.

Figure 2.6. The IconButton.

figure 2.6. the iconbutton.

To create the IconButton control the following three steps are required:

  1. Create a new Class Library project.

  2. Add references to System.Drawing.dll and System.Windows.Forms.dll.

  3. Create the IconButton.cs source.

To create the IconButton, start by creating a new Class Library project in VS .NET, as shown in Figure 2.7, with the name IconButton.

Figure 2.7. The IconButton project.

figure 2.7. the iconbutton project.

Note

The reason for creating a Class Library instead of a Windows Control Library is that a Windows Control Library assumes you are going to build a UserControl. As such, unnecessary references and project files are created.


As always, VS .NET provides a default class1.cs file and opens it within the editor. You can delete this file, or rename it to IconButton.cs as you chose. Next, add references to System.Drawing.dll and System.Windows.Forms.dll to the project. Right-clicking the project name and choosing the Add Reference menu option can be used to add the references.

With the project workspace set up and the necessary references in place, all that remains is to copy the source from Listing 2.6 for C# or Listing 2.7 for VB .NET, depending on the project language type you chose.

Listing 2.6 IconButton.cs C# Source
   1: ////////////////////////////////////////////////////////////////////////   2: ///File        :IconButton.cs   3: ///Author    :Richard L. Weeks   4: ///   5: /// Copyright (c) 2001 by Richard L. Weeks   6: /// This file is provided for instructional purposes only.   7: /// No warranties.   8: ////////////////////////////////////////////////////////////////////////   9:  10: using System;  11: using System.Windows.Forms;  12: using System.Drawing;  13:  14:  15: namespace SAMS.ToolKit.Controls {  16:     /// <summary>  17:     /// IconButton Class  18:     /// </summary>  19:     [System.ComponentModel.Description( "SAMS IconButton Control" )]  20:     public class IconButton : System.Windows.Forms.Control {  21:  22:  23:         #region STATIC MEMBER FIELDS  24:  25:         protected static int        EDGE_PADDING = 4;  26:  27:         #endregion  28:  29:         #region Implementation Member Fields  30:  31:         protected ButtonState        buttonState;  32:         protected Icon                buttonIcon;  33:         protected int                iconDrawWidth;  34:         protected bool                mousePressed;  35:  36:         #endregion  37:  38:  #region IconButton Properties  39:  40:         [  41:         System.ComponentModel.Description( "The Icon to be displayed in the button"  graphics/ccc.gif),  42:         System.ComponentModel.Category( "Appearance" ),  43:         System.ComponentModel.DefaultValue( null )  44:         ]  45:         public Icon Icon {  46:             get {  return buttonIcon; }  47:             set {  48:                 buttonIcon = value;  49:                 Invalidate( );  50:                 Update( );  51:             }  52:         }  53:  54:         #endregion  55:  56:  57:         #region Construction / Initialization  58:         /// <summary>  59:         /// Simple Constructor  60:         /// </summary>  61:         public IconButton( ) {  62:             InitializeComponent(  );  63:         }  64:  65:         /// <summary>  66:         /// Initialize the default values for the IconButton  67:         /// </summary>  68:         private void InitializeComponent( ) {  69:             buttonIcon        = null;  70:             buttonState        = ButtonState.Normal;  71:             mousePressed    = false;  72:         }  73:         #endregion  74:  75:         #region Control Method Overrides  76:  77:         /// <summary>  78:         ///  79:         /// </summary>  80:         /// <param name="e"></param>  81:         protected override void OnGotFocus( EventArgs e ) {  82:             Invalidate( );  83:    base.OnGotFocus( e );  84:         }  85:  86:         protected override void OnLostFocus( EventArgs e ) {  87:             Invalidate( );  88:             base.OnLostFocus( e );  89:         }  90:  91:         protected override void OnTextChanged( EventArgs e ) {  92:             Invalidate( );  93:             Update( );  94:             base.OnTextChanged( e );  95:         }  96:  97:         /// <summary>  98:         ///  99:         /// </summary> 100:         /// <param name="e"></param> 101:         protected override void OnSizeChanged( EventArgs e ) { 102:             base.OnSizeChanged( e ); 103:             this.Invalidate( ); 104:             this.Update( ); 105:         } 106: 107:         /// <summary> 108:         /// Render the IconButton 109:         /// </summary> 110:         /// <param name="e"><see cref="PaintEventArgs"/></param> 111:         protected override void OnPaint( PaintEventArgs e ) { 112:             base.OnPaint( e ); 113:             Draw( e.Graphics ); 114:         } 115: 116:         /// <summary> 117:         /// 118:         /// </summary> 119:         /// <param name="e"></param> 120:         protected override void OnMouseDown( MouseEventArgs e ) { 121:             if( e.Button == MouseButtons.Left ) { 122:       Focus( ); 123:                 Capture            = true; 124:                 buttonState        = ButtonState.Pushed; 125:                 mousePressed    = true; 126:                 Invalidate( ); 127:                 Update( ); 128:             }  else 129:                 base.OnMouseDown( e ); 130:         } 131: 132:         /// <summary> 133:         /// 134:         /// </summary> 135:         /// <param name="e"></param> 136:         protected override void OnMouseUp( MouseEventArgs e ) { 137: 138:             if( mousePressed && e.Button == MouseButtons.Left ) { 139:                 Capture            = false; 140:                 buttonState        = ButtonState.Normal; 141:                 Invalidate( ); 142:                 Update( ); 143:             }  else 144:                 base.OnMouseUp( e ); 145: 146:             mousePressed    = false; 147:         } 148: 149: 150: 151:         #endregion 152: 153:         #region Implementation 154: 155:         /// <summary> 156:         /// Render the IconButton 157:         /// </summary> 158:         /// <param name="g"></param> 159:         protected virtual void Draw( Graphics g ) { 160: 161:             DrawButton( g ); 162: 163:             if( buttonIcon != null ) 164:                 DrawIcon( g ); 165: 166:             DrawText( g ); 167: 168:             if( base.Focused ) 169:                 DrawFocusClues( g ); 170:         } 171: 172:         /// <summary> 173:         /// 174:         /// </summary> 175:         /// <param name="g"></param> 176:   protected virtual void DrawButton( Graphics g ) { 177:             Rectangle rcButton = new Rectangle( 0, 0, this.Width, this.Height ); 178:             if( Focused ) 179:                 rcButton.Inflate(-1,-1); 180: 181:             ControlPaint.DrawButton( g, rcButton, buttonState ); 182:         } 183: 184:         /// <summary> 185:         /// 186:         /// </summary> 187:         /// <param name="g"></param> 188:         protected virtual void DrawText( Graphics g ) { 189:             int left    = (buttonIcon == null ? 190:                 IconButton.EDGE_PADDING : 191:                 iconDrawWidth + IconButton.EDGE_PADDING); 192:             int width    = Width - left; 193:             int top        = IconButton.EDGE_PADDING; 194:             int height    = Height - (2*IconButton.EDGE_PADDING); 195: 196:             RectangleF layoutRect = new RectangleF( left, top, width, height ); 197:             if( ButtonState.Pushed == buttonState ) 198:                 layoutRect.Offset( 1f, 1f ); 199: 200:             StringFormat fmt    = new StringFormat( ); 201:             fmt.Alignment        = StringAlignment.Center; 202:             fmt.LineAlignment    = StringAlignment.Center; 203: 204:             SolidBrush textBrush    = new SolidBrush( this.ForeColor ); 205:             g.DrawString( Text, Font, textBrush, layoutRect, fmt ); 206: 207:             textBrush.Dispose( ); 208:         } 209: 210:         /// <summary> 211:         /// 212:         /// </summary> 213:         /// <param name="g"></param> 214:         protected virtual void DrawIcon( Graphics g ) { 215:             System.Diagnostics.Debug.Assert( buttonIcon != null, "IconButton Icon is  graphics/ccc.gifnull" ); 216: 217:             int top        = ((Height/2) - (buttonIcon.Height/2)); 218:             int height    = buttonIcon.Height; 219:             int width    = buttonIcon.Width; 220: 221:             if( (top + height) >= Height ) { 222:         //Scale the image to fit in (w,h) of button 223:                 top = IconButton.EDGE_PADDING; 224:                 int drawHeight = Height - (2*IconButton.EDGE_PADDING); 225:                 float scale = ((float)drawHeight / (float)height); 226:                 width = (int)((float)width*scale); 227:                 height = drawHeight; 228:             } 229:             Rectangle iconRect = new Rectangle( IconButton.EDGE_PADDING, top, width,  graphics/ccc.gifheight); 230: 231:             if( buttonState == ButtonState.Pushed ) 232:                 iconRect.Offset(1,1); 233: 234:             g.DrawIcon( buttonIcon, iconRect ); 235: 236:             this.iconDrawWidth = iconRect.Width; 237:         } 238: 239:         /// <summary> 240:         /// 241:         /// </summary> 242:         /// <param name="g"></param> 243:         protected virtual void DrawFocusClues( Graphics g ) { 244:             System.Drawing.Pen p = new Pen( System.Drawing.Color.Black, 1f ); 245:             Rectangle frameRect = new Rectangle( 0, 0, this.Width, this.Height ); 246:             g.DrawRectangle( p, frameRect ); 247: 248:             p.DashStyle = System.Drawing.Drawing2D.DashStyle.Dot; 249:             frameRect = new Rectangle( 2, 2, this.Width - 6, this.Height - 6); 250:             if( buttonState == ButtonState.Pushed ) 251:                 frameRect.Offset( 1, 1 ); 252:             g.DrawRectangle( p, frameRect ); 253: 254:             p.Dispose( ); 255:         } 256:         #endregion 257: 258:     } 259: } 

Even a small control can quickly reach a couple hundred lines of code. The C# version of the IconButton control, from Listing 2.6, is designed to mimic the standard Windows button in terms of look and feel while also providing the capability to associate an icon to be drawn on the button.

The drawing code for the button is broken down into three tasks. The first task is to draw the button itself. The method DrawButton on line 176 handles drawing the basic button control. After the button has been rendered, the next step is to draw the associated icon if there is one. The DrawIcon method on line 214 handles this task.

Rather than simply drawing the icon image as is, the DrawIcon method scales the icon as necessary to fit within the button. The final width of the renderend icon must also be tracked because the text for the button will need this information to align itself properly. The final basic drawing step is to render the button text using the DrawText method on line 188.

The DrawText method determines the alignment for the text depending on factors such as the icon draw width and the current state of the button. If the button is in a pushed state, the text is offset by one pixel. This offsetting makes it appear as if the button is being pushed down and gives a sense of movement to the user.

The next major area of the IconButton is dealing with events. The most common events deal with the mouse. The IconButton overrides both the OnMouseDown and the OnMouseUp events of the control base class. The mouse events are used to change the state of the button from normal to pushed and back to normal, depending on the actions of the mouse. Other events include the paint and size events, along with responding to the TextChanged event.

Listing 2.7 is the VB .NET equivalent of the C# source found in Listing 2.6. In every way, these two code listings provide for the same functionality.

Listing 2.7 IconButton VB .NET Source
   1: Imports System.Windows.Forms   2: Imports System.Drawing   3:   4: Namespace SAMS.ToolKit.VB.Controls   5:   6:     <System.ComponentModel.Description("SAMS IconButton Control (VB)")> _   7:     Public Class IconButton   8:         Inherits System.Windows.Forms.Control   9:  10: #Region "Const Member Fields"  11:         Protected Const EDGE_PADDING As Integer = 4  12: #End Region  13:  14: #Region "Implementation Member Fields"  15:         Protected buttonState As System.Windows.Forms.buttonState  16:         Protected buttonIcon As System.Drawing.Icon  17:         Protected mousePressed As Boolean  18:         Protected iconDrawWidth As Integer  19: #End Region  20:  21: #Region "Properties"  22:  23:         <System.ComponentModel.Description("The Icon to be displayed in the button"),  24:         System.ComponentModel.Category("Appearance")> _  25:         Public Property Icon() As Icon  26:             Get  27:                 Icon = buttonIcon  28:             End Get  29:             Set(ByVal value As Icon)  30:                 buttonIcon = value  31:                 Invalidate()  32:                 Update()  33:             End Set  34:         End Property  35: #End Region  36:  37:  38: #Region "Construction"  39:  40:         Public Sub IconButton()  41:             buttonState = buttonState.Normal  42:             buttonIcon = Nothing  43:             iconDrawWidth = 0  44:         End Sub  45:  46: #End Region  47:  48: #Region "Control Overrides"  49:  50:         Protected Overrides Sub OnMouseDown(ByVal e As  graphics/ccc.gifSystem.Windows.Forms.MouseEventArgs)  51:             If (e.Button = MouseButtons.Left) Then  52:                 Focus()  53:                 Capture = True  54:                 buttonState = buttonState.Pushed  55:                 mousePressed = True  56:                 Invalidate()  57:                 Update()  58:             Else  59:       MyBase.OnMouseDown(e)  60:             End If  61:         End Sub  62:  63:  64:         Protected Overrides Sub OnMouseUp(ByVal e As  graphics/ccc.gifSystem.Windows.Forms.MouseEventArgs)  65:             If (mousePressed And (e.Button = MouseButtons.Left)) Then  66:                 Capture = False  67:                 mousePressed = False  68:                 buttonState = buttonState.Normal  69:                 Invalidate()  70:                 Update()  71:             Else  72:                 MyBase.OnMouseUp(e)  73:             End If  74:         End Sub  75:  76:         Protected Overrides Sub OnPaint(ByVal e As  graphics/ccc.gifSystem.Windows.Forms.PaintEventArgs)  77:             Draw(e.Graphics)  78:             MyBase.OnPaint(e)  79:         End Sub  80:  81:        Protected Overrides Sub OnSizeChanged(ByVal e As System.EventArgs)  82:             Invalidate()  83:             MyBase.OnSizeChanged(e)  84:        End Sub  85:  86:        Protected Overrides Sub OnTextChanged(ByVal e As System.EventArgs)  87:             Invalidate()  88:        End Sub  89:  90:        Protected Overrides Sub OnLostFocus(ByVal e As System.EventArgs)  91:             Invalidate()  92:        End Sub  93:  94:        Protected Overrides Sub OnGotFocus(ByVal e As System.EventArgs)  95:             Invalidate()  96:        End Sub  97:  98: #End Region  99: 100: #Region "Implementation" 101:        Protected Overridable Sub Draw(ByRef g As System.Drawing.Graphics) 102:             DrawButton(g) 103:             If (Not buttonIcon Is Nothing) Then 104:                 DrawIcon(g) 105:             End If 106:             DrawText(g) 107: 108:  If (MyBase.Focused) Then 109:                 DrawFocusClues(g) 110:             End If 111:        End Sub 112: 113:         Protected Overridable Sub DrawButton(ByRef g As System.Drawing.Graphics) 114:             Dim rcButton As New Rectangle(0, 0, Width, Height) 115:             If (Focused) Then 116:                 rcButton.Inflate(-1, -1) 117:             End If 118:             ControlPaint.DrawButton(g, rcButton, buttonState) 119:         End Sub 120: 121:         Protected Overridable Sub DrawIcon(ByRef g As System.Drawing.Graphics) 122:             System.Diagnostics.Debug.Assert(Not buttonIcon Is Nothing, "IconButton  graphics/ccc.gifis null") 123: 124:             Dim top, height, width As Integer 125: 126:             top = (Me.Height / 2) - (buttonIcon.Height / 2) 127:             height = buttonIcon.Height 128:             width = buttonIcon.Width 129: 130:             If ((top + height) >= Me.Height) Then 131:                 'Scale the image to fit in (w,h) of button 132:                 top = EDGE_PADDING 133:                Dim drawHeight As Integer = Me.Height - (2 * EDGE_PADDING) 134:                Dim scale As Single = drawHeight / height 135:                 width = width * scale 136:                 height = drawHeight 137:             End If 138: 139:             Dim iconRect As New Rectangle(EDGE_PADDING, top, width, height) 140:             If (buttonState.Pushed = buttonState) Then 141:                 iconRect.Offset(1F, 1F) 142:             End If 143: 144:             g.DrawIcon(buttonIcon, iconRect) 145:             iconDrawWidth = iconRect.Width 146:         End Sub 147: 148:         Protected Overridable Sub DrawText(ByRef g As System.Drawing.Graphics) 149:             Dim top, left, width, height As Integer 150: 151:  top = EDGE_PADDING 152:             left = IIf(buttonIcon Is Nothing, EDGE_PADDING, iconDrawWidth +  graphics/ccc.gifEDGE_PADDING) 153:             width = Me.Width - left 154:             height = Me.Height - (2 * EDGE_PADDING) 155: 156:             Dim layoutRect As New RectangleF(left, top, width, height) 157:             If (buttonState.Pushed = buttonState) Then 158:                 layoutRect.Offset(1F, 1F) 159:             End If 160: 161:             Dim fmt As New StringFormat() 162:             fmt.Alignment = StringAlignment.Center 163:             fmt.LineAlignment = StringAlignment.Center 164: 165:             Dim textBrush As New SolidBrush(Me.ForeColor) 166: 167:             g.DrawString(Text, Font, textBrush, layoutRect, fmt) 168: 169:             textBrush.Dispose() 170: 171:         End Sub 172: 173:         Protected Overridable Sub DrawFocusClues(ByRef g As System.Drawing.Graphics) 174:             Dim p As New System.Drawing.Pen(System.Drawing.Color.Black, 1F) 175:             Dim frameRect = New Rectangle(0, 0, Me.Width, Me.Height) 176:             g.DrawRectangle(p, frameRect) 177: 178:             p.DashStyle = Drawing.Drawing2D.DashStyle.Dot 179:             frameRect = New Rectangle(2, 2, Me.Width - 6, Me.Height - 6) 180:             If (buttonState.Pushed = buttonState) Then 181:                 frameRect.offset(1, 1) 182:             End If 183:             g.DrawRectangle(p, frameRect) 184: 185:             p.Dispose() 186:         End Sub 187: #End Region 188: 189:     End Class 190: 191: End Namespace 

The code for both C# and VB .NET is remarkably similar in structure and syntax. In fact, all the topics covered in this book can be implemented in C# or VB .NET with ease. The .NET base class libraries have finally leveled the playing field such that you may use the language of your choice to accomplish the task at hand.

Most of the code for the IconButton is fairly simple in nature and makes use of GDI+, Graphics Device Interface, to draw the associated icon for the button. The topic of GDI+ is covered in Chapter 4, "GDI+." In addition, the IconButton uses the ControlPaint class to draw the button itself. Controls have two basic parts: presentation and logic.

The logic of a control depends on the purpose it's supposed to serve, and as such, developing two complete controls, both presented in this book, will help give you an understanding on that front. The presentation of a control consists of runtime and design-time behavior and the control's look and feel. Chapter 4, "GDI+," covers the use of GDI+ for dealing with the drawing aspects of a control, and the remaining chapters cover VS .NET support for control development.



    .NET Windows Forms Custom Controls
    User Interfaces in VB .NET: Windows Forms and Custom Controls
    ISBN: 1590590449
    EAN: 2147483647
    Year: 2002
    Pages: 74

    flylib.com © 2008-2017.
    If you may any questions please contact us: flylib@qtcs.net