Drawing Your Own Interface

If you need to create an interface that is different from any of the controls you currently have access to, you can always turn to drawing your own interface. When developing business applications, the standard set of controls are usually sufficient. Sometimes though, doing your own graphics is the only way to get the results you want. Consider the following control; I wanted to draw a series of messages into a window (tip-of-the-day type of information) and have each new message slowly fade-in over the top of the previous one. I could have implemented this using a label that I slowly changed the ForeColor on, but I plan on adding images and other aspects to the message in the future, so drawing my own control gives me the most flexibility.

To get started on any custom drawn control, create a new class that inherits from System.Windows.Forms.Control, and then override OnPaint to add your own graphics code. There's a bit more code needed in order to track the current message and to track the current stage in the animation. The result is a message block that fades in and fades out as it moves through a list of messages to display. Listing 8.6 shows the OnPaint routine where the drawing occurs. This routine handles drawing each phase of the animation from stop to go.

Listing 8.6. Writing Your Own OnPaint Routine Is the Key to Drawing Your Own Control
Public Enum AnimationStage
    fadingIn
    stayingPut
    fadingOut
End Enum

Public Class MessageDisplayer
    Inherits System.Windows.Forms.Control
Const ANIMATION_STEPS As Integer = 10
Dim currentStage As AnimationStage _
    = AnimationStage.fadingIn
Dim m_Messages As String() _
    = {"No Messages", "No Really"}
Dim m_currentMessage As Integer = 0
Dim m_previousMessage As Integer = 0
Dim m_interval As Integer = 1
Dim m_currentStep As Integer = 0
Dim WithEvents m_timer As Timer

Private Sub m_timer_Tick( _
        ByVal sender As Object, _
        ByVal e As System.EventArgs) _
        Handles m_timer.Tick
    If Me.m_currentStep < Me.ANIMATION_STEPS Then
        Me.m_currentStep += 1
        Me.Invalidate()
    Else
        Me.m_currentStep = 0
        Select Case Me.currentStage
            Case AnimationStage.fadingIn
                Me.currentStage = AnimationStage.stayingPut

            Case AnimationStage.fadingOut
                If Me.m_currentMessage < _
                        Me.m_Messages.Length - 1 Then
                    Me.m_currentMessage += 1
                Else
                    Me.m_currentMessage = 0
                End If
                Me.currentStage = AnimationStage.fadingIn

            Case AnimationStage.stayingPut
                Me.currentStage = AnimationStage.fadingOut
        End Select
        Me.Invalidate()
    End If
End Sub


Protected Overrides Sub OnPaint( _
        ByVal e As PaintEventArgs)

    Dim alpha As Integer
    Select Case Me.currentStage

        Case AnimationStage.stayingPut
            e.Graphics.Clear(Me.BackColor)
            alpha = 255

        Case AnimationStage.fadingIn
            e.Graphics.Clear(Me.BackColor)
            alpha = (256  ANIMATION_STEPS) _
                        * Me.m_currentStep

        Case AnimationStage.fadingOut
            e.Graphics.Clear(Me.BackColor)
            alpha = 255 - ((256  ANIMATION_STEPS) _
                        * Me.m_currentStep)

    End Select
    Debug.WriteLine(alpha)

    Dim fColor As Color _
        = Color.FromArgb(alpha, Me.ForeColor)
    Dim message As String = Me.m_Messages( _
        m_currentMessage)
    Dim layoutRect As Drawing.RectangleF
    layoutRect = New Drawing.RectangleF( _
        0, 0, Me.Width, Me.Height)
    layoutRect.Inflate(-10, -10)
    Dim messageBrush As Brush _
        = New SolidBrush(fColor)

    Dim myFormat As New _
        StringFormat(StringFormatFlags.LineLimit)
    myFormat.Trimming = _
        StringTrimming.EllipsisWord
    myFormat.Alignment = _
        StringAlignment.Center

    e.Graphics.SmoothingMode = _
        Drawing2D.SmoothingMode.AntiAlias
    e.Graphics.DrawString( _
        message, Me.Font, _
        messageBrush, layoutRect, myFormat)
End Sub
End Class
				

To reduce flicker when handling your own graphics, there are some useful control level settings you can configure. The first three settings (shown in Listing 8.7) produce the least amount of flicker possible. Because this text is being wrapped and sized to fit the available space, it will need to be redrawn whenever the size of the control changes, which is handled by the fourth setting ResizeRedraw.

Listing 8.7. These Control-Level Settings Can Help to Prevent Flicker and to Ensure that the Control Redraws as Needed
Public Sub New()
    Me.SetStyle(ControlStyles.AllPaintingInWmPaint, True)
    Me.SetStyle(ControlStyles.UserPaint, True)
    Me.SetStyle(ControlStyles.DoubleBuffer, True)

    Me.SetStyle(ControlStyles.ResizeRedraw, True)
    SetupTimer()
End Sub

The call to SetupTimer in Listing 8.7 is one of the many small details of this sample code that is not shown in the in-book listings. Download this chapter's code to see the full set of code for this and all the other controls covered here.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.129.20.133