Gradient on a Button

DiverDan

Well-known member
Joined
Jan 16, 2003
Messages
645
Location
Sacramento, CA
User Rank
*Experts*
I have little to no experience on programming gradients or programming graphics for that matter, but have been digitally drawing them for bunches of years. I have moved up to a level of mass confusion while searching the net for examples of how to paint a gradient on a popup style button. I would appreciate any help on this.

Thanks
Dan
 
Its probably more trouble than its worth. Making your own button
control that supports gradients would be much simpler, most likely.
 
Check out the System.Drawing.Drawing2d.LinearGradientBrush class.
 
Hi divil, Heres what I have so far that produces nothing:

Private Sub Button1_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles Button1.Paint

PaintGradient(Color.AliceBlue, Color.SteelBlue, Drawing.Drawing2D.LinearGradientMode.Vertical)
End Sub

Private Sub PaintGradient(ByVal TopColor As Color, ByVal BottomColor As Color, ByVal mode As System.Drawing.Drawing2D.LinearGradientMode)

Dim a As New System.Drawing.Drawing2D.LinearGradientBrush(New RectangleF(0, 0, Me.Width, Me.Height), TopColor, BottomColor, mode)
Dim g As Graphics = Me.CreateGraphics
g.FillRectangle(a, New RectangleF(0, 0, Me.Width, Me.Height))
g.Dispose()
End Sub

Thanks
Dan
 
Code:
Imports System
Imports System.Collections
Imports System.ComponentModel
Imports System.Drawing
Imports System.Drawing.Drawing2D
Imports System.Data
Imports System.Windows.Forms
Imports System.ComponentModel.Design.Serialization

Namespace Usercontrols

    Public Class gradiant_button
        Inherits System.Windows.Forms.Button

        Private _OutlineColor As Color = Color.White
        Private _FillColor As Color = Color.Gray
        Private _FillColor_Gradiant As Color = Color.SteelBlue
        Private _FillColorDisabled As Color = Color.LightGray
        Private _FillColorDisabled_Gradiant As Color = Color.Gray
        Private _FillColorHover As Color = Color.Beige
        Private _FillColorHover_Gradiant As Color = Color.Beige
        Private _TextColor As Color = Color.Black
        Private _TextColor_Gradiant As Color = Color.Black
        Private SwapMouse As Boolean = False
        Private DownMouse As Boolean = False

#Region "Coloring code & Properties"

        Public Property FillColor() As Color
            Get
                Return _FillColor
            End Get
            Set(ByVal Value As Color)
                _FillColor = Value
                Invalidate()
            End Set
        End Property

        Public Property FillColor_Gradiant() As Color
            Get
                Return _FillColor_Gradiant
            End Get
            Set(ByVal Value As Color)
                _FillColor_Gradiant = Value
                Invalidate()
            End Set
        End Property

        Public Property FillColorDisabled() As Color
            Get
                Return _FillColorDisabled
            End Get
            Set(ByVal Value As Color)
                _FillColorDisabled = Value
                Invalidate()
            End Set
        End Property

        Public Property FillColorDisabled_Gradiant() As Color
            Get
                Return _FillColorDisabled_Gradiant
            End Get
            Set(ByVal Value As Color)
                _FillColorDisabled_Gradiant = Value
                Invalidate()
            End Set
        End Property

        Public Property FillColorHover() As Color
            Get
                Return _FillColorHover
            End Get
            Set(ByVal Value As Color)
                _FillColorHover = Value
                Invalidate()
            End Set
        End Property

        Public Property FillColorHover_Gradiant() As Color
            Get
                Return _FillColorHover_Gradiant
            End Get
            Set(ByVal Value As Color)
                _FillColorHover_Gradiant = Value
                Invalidate()
            End Set
        End Property

        Public Property TextColor() As Color
            Get
                Return _TextColor
            End Get
            Set(ByVal Value As Color)
                _TextColor = Value
                Invalidate()
            End Set
        End Property

        Public Property TextColor_Gradiant() As Color
            Get
                Return _TextColor_Gradiant
            End Get
            Set(ByVal Value As Color)
                _TextColor_Gradiant = Value
                Invalidate()
            End Set
        End Property

#End Region

#Region " Windows Form Designer generated code "

        Public Sub New()
            MyBase.New()
            This call is required by the Windows Form Designer.
            InitializeComponent()
            Add any initialization after the InitializeComponent() call
            SetStyle(ControlStyles.AllPaintingInWmPaint, True)
            SetStyle(ControlStyles.DoubleBuffer, True)
            SetStyle(ControlStyles.ResizeRedraw, True)
        End Sub

        UserControl overrides dispose to clean up the component list.
        Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
            If disposing Then
                If Not (components Is Nothing) Then
                    components.Dispose()
                End If
            End If
            MyBase.Dispose(disposing)
        End Sub

        Required by the Windows Form Designer
        Private components As System.ComponentModel.IContainer

        NOTE: The following procedure is required by the Windows Form Designer
        It can be modified using the Windows Form Designer.  
        Do not modify it using the code editor.
        <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
            
            outline_button
            
            Me.Name = "outline_button"
            Me.Size = New System.Drawing.Size(62, 62)
        End Sub

#End Region

#Region "Paint and Mouse"

        Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
            Dim GradiantBrush As Brush
            Dim TextBrush As Brush
            Dim HoverBrush As Brush
            Dim DisabledBrush As Brush
            Dim StringSize As New SizeF()

             Setup gradiants into the brushes 3, Text, Hover, Normal
            HoverBrush = New Drawing2D.LinearGradientBrush(New Point(0, 0), New Point(0, Me.Height), Me.FillColorHover, Me.FillColorHover_Gradiant)
            GradiantBrush = New Drawing2D.LinearGradientBrush(New Point(0, 0), New Point(0, Me.Height), Me._FillColor, Me._FillColor_Gradiant)
            TextBrush = New Drawing2D.LinearGradientBrush(New Point(0, 0), New Point(0, Me.Height), Me._TextColor, Me._TextColor_Gradiant)
            DisabledBrush = New Drawing2D.LinearGradientBrush(New Point(0, 0), New Point(0, Me.Height), Me._FillColorDisabled, Me._FillColorDisabled_Gradiant)

             if mouse hovering
            If Me.Enabled Then
                If Me.SwapMouse = True Then
                    e.Graphics.FillRectangle(HoverBrush, ClientRectangle)
                Else
                    e.Graphics.FillRectangle(GradiantBrush, ClientRectangle)
                End If
            Else
                e.Graphics.FillRectangle(DisabledBrush, ClientRectangle)
            End If

             if mouse button down change border style
            If Me.DownMouse = True And Me.Enabled Then
                ControlPaint.DrawBorder3D(e.Graphics, ClientRectangle, Border3DStyle.Bump)
            Else
                ControlPaint.DrawBorder3D(e.Graphics, ClientRectangle, Border3DStyle.Etched)
            End If

             text centred in button
            StringSize = e.Graphics.MeasureString(Text, Font)
            e.Graphics.DrawString(Text, Font, TextBrush, Convert.ToInt32(Width / 2) - Convert.ToInt32(StringSize.Width / 2), Convert.ToInt32(Height / 2) - Convert.ToInt32(StringSize.Height / 2))
        End Sub

#Region "Mouse events"

        Protected Overrides Sub OnMouseLeave(ByVal e As System.EventArgs)
            Me.SwapMouse = False
            Me.Refresh()
            MyBase.OnMouseLeave(New EventArgs())
        End Sub

        Protected Overrides Sub OnMouseEnter(ByVal e As System.EventArgs)
            Me.SwapMouse = True
            Me.Refresh()
            MyBase.OnMouseEnter(New EventArgs())
        End Sub

        Protected Overrides Sub OnMouseDown(ByVal e As System.Windows.Forms.MouseEventArgs)
            Me.DownMouse = True
            Me.Refresh()
            MyBase.OnMouseDown(e)
        End Sub

        Protected Overrides Sub OnMouseUp(ByVal e As System.Windows.Forms.MouseEventArgs)
            Me.DownMouse = False
            Me.Refresh()
            MyBase.OnMouseUp(e)
        End Sub

#End Region

#End Region

        Protected Overrides Sub OnValidated(ByVal e As System.EventArgs)
            Me.Refresh()
        End Sub

    End Class

End Namespace

This is a fairly simple user control with gradiants with hover and text gradiants.

to use Click on project->Add user control

and paste the code

and use


Andy
 
Hi Diverdan..

You are on the right track, but youve missed one imported thing:

Code:
Private Sub Button1_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles Button1.Paint

PaintGradient(Color.AliceBlue, Color.SteelBlue, Drawing.Drawing2D.LinearGradientMode.Vertical,e.Graphics,sender)
End Sub

Private Sub PaintGradient(ByVal TopColor As Color, ByVal BottomColor As Color, ByVal mode As System.Drawing.Drawing2D.LinearGradientMode,g as Graphics,target as Control)

Dim a As New System.Drawing.Drawing2D.LinearGradientBrush(New RectangleF(0, 0, target.Width, target.Height), TopColor, BottomColor, mode)

g.FillRectangle(a, New RectangleF(0, 0, target.Width, target.Height))
g.Dispose()
End Sub

You can see Ive only added a graphics object to your function, rather than creating one in the function... (by the way, youve created a graphics surface of your form, not the button)
Ive also added a control parameter to the function that will determine the size of the area/rectangle..

So you can see that you were close... :)
 
Be careful when you call Dispose() on a Graphics object. Cywizz, your example is not creating the Graphics object and therefore shouldnt Dispose of it. Only when you create one through CreateGraphics should you Dispose of it.

-Nerseus
 
good spot... I just copied dds code and added the parameters, but you are right, it usually also generates a error when trying to do so.
The brush (a) should be disposed of in the above example.

(Pens, brushes and Graphic objects must be disposed if created)

Cheers... :)
 
I ended up making a few mods on Andys code to also indent the text a bit on mouse down.

Code:
        StringSize = e.Graphics.MeasureString(Me._Text, Me.textFont)

         if mouse button down change border style
        If Me.DownMouse = True Then
            ControlPaint.DrawBorder3D(e.Graphics, ClientRectangle, Border3DStyle.Bump)
            e.Graphics.DrawString(Me._Text, Me.textFont, TextBrush, Convert.ToInt32(Me.Width / 2) - Convert.ToInt32(StringSize.Width / 2) + 1, Convert.ToInt32(Me.Height / 2 + 1) - Convert.ToInt32(StringSize.Height / 2) + 1 / 2)
        Else
            ControlPaint.DrawBorder3D(e.Graphics, ClientRectangle, Border3DStyle.Etched)
            e.Graphics.DrawString(Me._Text, Me.textFont, TextBrush, Convert.ToInt32(Me.Width / 2) - Convert.ToInt32(StringSize.Width / 2), Convert.ToInt32(Me.Height / 2) - Convert.ToInt32(StringSize.Height / 2))
        End If

Sorry, Im still a bit old fashioned and still like to see the button and text move together.

I think this User control is pretty nice!!! Thanks again Andy!

The only thing it now lacks is TabIndex support, which would be really nice.

Thanks again
Dan
 
Last edited by a moderator:
Added focus look as requested example project with control source

Andy

Just to add, I have removed binarys :)

[edit] You missed one - divil [/edit]
 

Attachments

Last edited by a moderator:
Thanks Andy, this is looking great!

Although Im having a problem loading your class into my project?

Im getting the following error message:

The user control gradient_button could not be loaded. Ensure that the library containing the control has been built and a project reference has been made to the library containg the control. If you have changed the name of the user control , close and re-open then controls desigener to update the toolbox item.

I really like your gradient button and would like to use it in my projects. Please help.

I changed the dash "focus " line a bit to put it to the outside regions of the button to be less obstrusive to the gradient:

Dim OutlinePen As New Pen(ForeColor)
OutlinePen.DashStyle = DashStyle.Dot
If (Me.DownMouse = True And Me.Enabled) Then
e.Graphics.DrawRectangle(OutlinePen, 10, 10, Me.Width - 16, Me.Height - 16)
e.Graphics.DrawRectangle(OutlinePen, 3, 3, Me.Width - 6, Me.Height - 6)
Else
e.Graphics.DrawRectangle(OutlinePen, 8, 7, Me.Width - 16, Me.Height - 15)
e.Graphics.DrawRectangle(OutlinePen, 2, 2, Me.Width - 6, Me.Height - 6)
End If
OutlinePen.Dispose()
End If

and changed the text offset back to:

if mouse button down change border style
If (Me.DownMouse = True And Me.Enabled) Then
ControlPaint.DrawBorder3D(e.Graphics, ClientRectangle, Border3DStyle.Bump)
e.Graphics.DrawString(Text, Font, TextBrush, Convert.ToInt32(Width / 2) - Convert.ToInt32(StringSize.Width / 2) + 1, Convert.ToInt32(Height / 2) - Convert.ToInt32(StringSize.Height / 2) + 1 / 2)
Else
ControlPaint.DrawBorder3D(e.Graphics, ClientRectangle, Border3DStyle.Etched)
e.Graphics.DrawString(Text, Font, TextBrush, Convert.ToInt32(Width / 2) - Convert.ToInt32(StringSize.Width / 2), Convert.ToInt32(Height / 2) - Convert.ToInt32(StringSize.Height / 2))
End If

I guess these changes reflect the artist side of me, sorry but its there.


Im only useing VB.Net Standard :-( and cannot complie this control into a dll. With these modifications, I think this gradient button control is perfect. Maybe a dll would work better simular to divils widgets, which is also a great control.

Thanks
Dan
 
Last edited by a moderator:
Back
Top