Click here to Skip to main content
15,860,844 members
Articles / Programming Languages / C#
Tip/Trick

Hot Track Buttons Windows 7 style using Windows Forms

Rate me:
Please Sign up or sign in to vote.
1.00/5 (2 votes)
9 May 2010CPOL 9K   3  
Title: Windows Forms Application Hot Track Button (Windows 7 Style)Author: Paul GoldhawkEmail: paul@k2workflow.comMember ID: 3518484Language: C#Platform: WindowsTechnology: Windows FormsLevel: AdvancedDescription: How to create windows forms hot...
MSIL
Title:       Windows Forms Application Hot Track Button (Windows 7 Style)
Author:      Paul Goldhawk
Email:       paul@k2workflow.com
Member ID:   3518484
Language:    C#
Platform:    Windows
Technology:  Windows Forms
Level:       Advanced
Description: How to create windows forms hot track buttons.
Section      Windows Forms UI
SubSection   Button Paint Overrides
License:     GNU

Introduction
I created the code to give my applications the Windows 7 feel and not be bound by the WPF themes. In my research in to how to do it I saw a great deal of developers looking for similar things. So here is my solution to the problem.
Background
I first did this as a button then I moved it to a User Control with numerous overloads.
Using the code
In order to use the code Copy the CustomControl to your project change the namespace to you projects namespace and compile. You should the see it in your toolbox.
In order to use the button click event toy will need to subscribe to the controls event by adding the following code to the load of your form.
<code>//
// Subscribe to the Controls Click event
//
sC_Button1.SC_Button_Clicked += new SC_Button.SC_Button_ClickEventr(SC_Button_Clicked);
//
// Create a method to handle the event
//
void SC_Button_Clicked(object sender, EventArgs e)
{
    Environment.Exit(0);
}</code>
Points of Interest
In order to get a similar effect to the HotTrack effects I need to use a LinearGradientBrush at an angle roughly 90 degrees to the position of the mouse whilst over the control. In order to do this without using sine functions I chose to use 45 * X mouse position in the control where the left of the control is -1 and the right of the control is +1. I used this angle to set the Gradient of the LinearGradientBrush.
In order for the button click to work I bubbled up the click event to the User Control

This is a sample of the custom user control that I made. If you want shaped buttons then you can use transparent images with a solid border of the shape that you would like. Bear in mind though it should match the form or control that the control is on.

<code>
#region -- Unsing --
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing.Drawing2D;
#endregion
namespace WindowsFormsApplication1
{
    public partial class SC_Button : UserControl
    {
        #region -- Delegates --
        public delegate void SC_Button_ClickEventr(object sender, EventArgs e);
        #endregion
        #region -- Events --
        public event SC_Button_ClickEventr SC_Button_Clicked;
        #endregion
        #region -- Public Properties --
        #region - button backgrounds -
        private Color _buttonUpTopColour = Color.FromArgb(100, 100, 100);
        public Color ButtonUpTopColour
        {
            get { return _buttonUpTopColour; }
            set { _buttonUpTopColour = value; }
        }
        private Color _buttonUpBottomColour = Color.Black;
        public Color ButtonUpBottomColour
        {
            get { return _buttonUpBottomColour; }
            set { _buttonUpBottomColour = value; }
        }
        private Color _buttonDownTopColour = Color.LightGreen;
        public Color ButtonDownTopColour
        {
            get { return _buttonDownTopColour; }
            set { _buttonDownTopColour = value; }
        }
        private Color _buttonDownBottomColour = Color.DarkGreen;
        public Color ButtonDownBottomColour
        {
            get { return _buttonDownBottomColour; }
            set { _buttonDownBottomColour = value; }
        }
        private Color _buttonPressedTopColour = Color.DarkGreen;
        public Color ButtonPressedTopColour
        {
            get { return _buttonPressedTopColour; }
            set { _buttonPressedTopColour = value; }
        }
        private Color _buttonPressedBottomColour = Color.DarkGreen;
        public Color ButtonPressedBottomColour
        {
            get { return _buttonPressedBottomColour; }
            set { _buttonPressedBottomColour = value; }
        }
        #endregion
        #region - button images
        private Image _buttonBorderMask;
        public Image ButtonBorderMask
        {
            get { return _buttonBorderMask; }
            set { _buttonBorderMask = value; }
        }
        private Image _buttonImage;
        public Image ButtonImage
        {
            get { return _buttonImage; }
            set { _buttonImage = value; }
        }
        private ContentAlignment _buttonImageAlign;
        public ContentAlignment ButtonImageAlign
        {
            get { return _buttonImageAlign; }
            set { _buttonImageAlign = value; }
        }
        #endregion
        #region - button text -
        public string ButtonText
        {
            get { return _scButton.Text; }
            set { _scButton.Text = value; }
        }
        #endregion
        #endregion
        #region -- Private Properties --
        private bool _onButton = false;
        private bool _isPressed = false;
        #endregion
        #region -- set the button to fill the control --
        public SC_Button()
        {
            InitializeComponent();
        }
        #endregion
        #region -- draw overrrides --
        private LinearGradientBrush getBrush(Control c)
        {
            if (_onButton)
            {
                if (_isPressed)
                {
                    return new LinearGradientBrush(new Rectangle(0, 0, c.Width, c.Height), _buttonPressedTopColour, _buttonPressedBottomColour, -90.0f, true);
                }
                else
                {
                    //
                    // get the position of the cursor on the control (1 = left hand side, and -1 = roght hand side)
                    //
                    float xPosOnButton = -2.0f * ((float)c.PointToClient(Cursor.Position).X - ((float)c.Width) / 2) / (float)c.Width;
                    float f = 45.0f * xPosOnButton;
                    return new LinearGradientBrush(new Rectangle(0, 0, c.Width, c.Height), _buttonDownTopColour, _buttonDownBottomColour, f - 90.0f, true);
                }
            }
            else
            {
                return new LinearGradientBrush(new Rectangle(0, 0, c.Width, c.Height), _buttonUpBottomColour, _buttonUpTopColour, -90.0f, true);
            }
        }
        private void paint_Background(PaintEventArgs e, Control c)
        {
            if (e == null)
                return;
            if (e.Graphics == null)
                return;
            Graphics g = e.Graphics;
            //
            // get the region to draw
            //
            System.Drawing.Rectangle rect = new Rectangle(0, 0, c.Width, c.Height);
            //
            // get color of background
            //
            System.Drawing.Color color = (c as Control).BackColor;
            //
            // get the brush
            //
            LinearGradientBrush brush = getBrush(c);
            //
            // fill the rectangle
            //
            g.FillRectangle(brush, rect);
            //
            //draw the image on the button
            //You can add alignment properties here
            // i have defaultes to left center
            //
            if (_buttonImage != null)
            {
                Rectangle imageRect = new Rectangle();
                //
                // set the image alignment
                //
                switch (_buttonImageAlign)
                {
                    case ContentAlignment.BottomCenter:
                        imageRect = new Rectangle((rect.Width - _buttonImage.Size.Width) / 2, rect.Height - _buttonImage.Size.Height, _buttonImage.Size.Width, _buttonImage.Size.Height);
                        break;
                    case ContentAlignment.BottomLeft:
                        imageRect = new Rectangle(2, rect.Height - _buttonImage.Size.Height - 2, _buttonImage.Size.Width, _buttonImage.Size.Height);
                        break;
                    case ContentAlignment.BottomRight:
                        imageRect = new Rectangle(rect.Width - _buttonImage.Size.Width - 2, rect.Height - _buttonImage.Size.Height - 2, _buttonImage.Size.Width, _buttonImage.Size.Height);
                        break;
                    case ContentAlignment.MiddleCenter:
                        imageRect = new Rectangle((rect.Width - _buttonImage.Size.Width) / 2, (rect.Height - _buttonImage.Size.Height) / 2, _buttonImage.Size.Width, _buttonImage.Size.Height);
                        break;
                    case ContentAlignment.MiddleLeft:
                        imageRect = new Rectangle(2, (rect.Height - _buttonImage.Size.Height) / 2, _buttonImage.Size.Width, _buttonImage.Size.Height);
                        break;
                    case ContentAlignment.MiddleRight:
                        imageRect = new Rectangle(rect.Width - _buttonImage.Size.Width - 2, (rect.Height - _buttonImage.Size.Height) / 2, _buttonImage.Size.Width, _buttonImage.Size.Height);
                        break;
                    case ContentAlignment.TopCenter:
                        imageRect = new Rectangle((rect.Width - _buttonImage.Size.Width) / 2, 2, _buttonImage.Size.Width, _buttonImage.Size.Height);
                        break;
                    case ContentAlignment.TopLeft:
                        imageRect = new Rectangle(2, 2, _buttonImage.Size.Width, _buttonImage.Size.Height);
                        break;
                    case ContentAlignment.TopRight:
                        imageRect = new Rectangle(rect.Width - _buttonImage.Size.Width - 2, 2, _buttonImage.Size.Width, _buttonImage.Size.Height);
                        break;
                }
                g.DrawImage(_buttonImage, imageRect);
            }
            //
            //draw the image to give rounded edges
            //
            if (_buttonBorderMask != null)
            {
                g.DrawImage(_buttonBorderMask, rect);
            }
            //
            // release resources
            //
            brush.Dispose();
        }
        private void paint_Text(PaintEventArgs e, Control c)
        {
            if (e == null)
                return;
            if (e.Graphics == null)
                return;
            System.Drawing.Rectangle rect = e.ClipRectangle;
            //
            // caculate bounding rectagle for the text
            //
            System.Drawing.SizeF size = e.ClipRectangle.Size;
            //
            // calculate the starting location to paint the text
            //
            Graphics g = c.CreateGraphics();
            int width = (int)g.MeasureString(c.Text, c.Font).Width;
            int height = (int)g.MeasureString(c.Text, c.Font).Height;
            g.Dispose();
            System.Drawing.Point pt = new Point((c.Width - width) / 2, (c.Height - height) / 2);
            //
            // paint text
            //
            e.Graphics.DrawString(c.Text, c.Font, new SolidBrush(Color.White), pt.X, pt.Y);
        }
        #endregion
        #region -- flag setting methods for button effects --
        private void _scButton_MouseDown(object sender, MouseEventArgs e)
        {
            _isPressed = true;
        }
        private void _scButton_MouseEnter(object sender, EventArgs e)
        {
            _onButton = true;
        }
        private void _scButton_MouseMove(object sender, MouseEventArgs e)
        {
            (sender as Control).Refresh();
        }
        private void _scButton_MouseLeave(object sender, EventArgs e)
        {
            _onButton = false;
        }
        private void _scButton_MouseUp(object sender, MouseEventArgs e)
        {
            _isPressed = false;
        }
        private void _scButton_Paint(object sender, PaintEventArgs e)
        {
            paint_Background(e, (sender as Control));
            paint_Text(e, (sender as Control));
        }
        #endregion
        private void SC_Button_Load(object sender, EventArgs e)
        {
            _scButton.Width = (sender as Control).Width;
            _scButton.Height = (sender as Control).Height;
            _scButton.Left = 0;
            _scButton.Top = 0;
        }
        void _scButton_Click(object sender, System.EventArgs e)
        {
            if (SC_Button_Clicked != null)
            {
                SC_Button_Clicked(sender, e);
            }
        }
    }
}</code>

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
South Africa South Africa
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
-- There are no messages in this forum --