Gradientowy PushButton

grad3.png

Cel artykułu

Artykuł pokazuje, jak zrobić własną kontrolkę Button wypełnioną gradientem, która ma bardzo prostą funcjonalność i bardzo prosty kod.

Chodziło o to, aby kontrolka na etapie wizualnego projektowania była w Toolboxie gotowa do położenia na formę, aby można było dopasować kolory gradientu również na tym etapie, wpisać tekst widoczny na kontrolce, a docelowo użyć w kodzie zdarzenia Click buttona.

Można spotkać różne podejścia do tematu np. umieszczenie komponentu Button, umieszczenie elementu PaintBox, także dwa komponenty – Button i Label, czy też umieszczenie w BackgroundImage obrazka z gradientowym tłem wygenerowanego w innym programie.

W przykładzie te dodatkowe komponenty nie występują. Stworzenie buttona ogranicza się do dodania do projektu elementu UserControl i zdefiniowania klasy potomnej w kodzie. Potrzebny kod jest poniżej.

Kod powstał w VS C# Express 2010 (WindowsForms).

Realizacja w C# - kod

using System;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;
using System.Drawing.Drawing2D; 

namespace WindowsFormsApplication1
{
    public partial class TBtn : UserControl
    {
        Color colorGradTop = Color.Navy; // kolor występujący na górze gradientowego tła
        Color colorGradBottom = Color.Red; // kolor występujący u dołu tła
        bool down = false; // flaga pozwalająca na odróżnienie sytuacji button myszki wciśnięty/puszczony od której zależy sposób malowania tła
        string text = "Sample text"; // przykładowy tekst do sprawdzenia jak dany kolor tekstu wygląda na danym tle
        LinearGradientBrush gradient; // brush wypełniający gradientem, który jest dostępny w System.Drawing.Drawing2D
        Rectangle rect; // prostokąt równoważny całemu obszarowi buttona

        public TBtn()
        {
            InitializeComponent();

            // domyślnie skalowanie kontrolek odbywa się w oparciu o użytą czcionkę
            // jednak zmiana czcionki kiedy forma już jest zaprojektowana może prowadzić do pozmieniania się rozmiarów kontrolek
            AutoScaleMode = AutoScaleMode.None;
 
            Font = new Font("Tahoma", 8, FontStyle.Bold); // przykładowa czcionka która od lat występuje w Windows
            AccessibleRole = AccessibleRole.PushButton; // sposób który pozwala uniknąć umieszczania dodatkowego buttona na UserControl
            DoubleBuffered = true; // zmniejszenie efektu migotania tła podczas kliknięcia
            ForeColor = Color.White; // kolor tekstu
            
            // poniżej lista zdarzeń wraz z funkcjami które te zdarzenia obsługują
            // użyty zapis sprowadza się do wpiasnia po nazwie zdarzenia (np. Paint) += new i dwukrotnego wciśnięcia klawisza TAB
            // po czym w kodzie automatycznie zostaje dodana funkcja obsługi zdarzenia do uzupełnienia

            Paint += new PaintEventHandler(TBtn_Paint);  // malowanie tła
            MouseDown += new MouseEventHandler(TBtn_MouseDown); // naciśnięcie klawisza myszki
            MouseUp += new MouseEventHandler(TBtn_MouseUp); // puszczenie klawisza myszki
            Click += new EventHandler(TBtn_Click); // kliknięcie na buttonie (naciśnięcie i puszczenie klawisza myszki)
            ForeColorChanged += new EventHandler(TBtn_ForeColorChanged); // reakcja na zmianę koloru tekstu
        }

        // w dalszym kodzie warto zwrócić uwagę na zapis [Browsable(true)]
        // dzięki niemu dana własność buttona np. ColorGradientTop staje się dostępna na etapie wizualnego projektowania formy
        // można wybrać kolor z palety kolorów przez zwykłe kliknięcie koloru na palecie

        // efektem działania Invalidate() jest przemalowanie całego buttona

        void TBtn_ForeColorChanged(object sender, EventArgs e) 
        { 
            Invalidate(); 
        }

        void TBtn_Click(object sender, EventArgs e) 
        { 
            // kliknięcie przy stanie początkowym down = false wymaga powrotu do tego stanu
            // bo najpierw zaszło MouseDown które które przestawiła flagę down na true

            down = false; 
            Invalidate(); 
        }

        void TBtn_MouseUp(object sender, MouseEventArgs e) 
        { 
            // obsługa MouseUp jest istotna kiedy użytkownik po MouseDown wyszedł kursorem myszy poza obszar kontrolki i dopiero puścił klawisz myszy
            // w takiej sytuacji nie wykona się Click

            down = false; 
            Invalidate(); 
        }

        void TBtn_MouseDown(object sender, MouseEventArgs e) 
        { 
            // reakcja na naciśnięcie klawisza myszy i trzymania go wciśniętym

            down = true; 
            Invalidate(); 
        }

        // poniższe własności są widoczne w oknie Properties

        [Browsable(true)]
        public string Caption
        {
            get  // funkcja zwracająca wartość własności
            { 
                 return text; 
            }
            set  // funkcja ustawiająca warość własności
            { 
                 text = value; 
                 Invalidate(); 
            }
        }

        [Browsable(true)]
        public Color ColorGradientTop 
        {
            get 
            { 
                return colorGradTop; 
            }
            set 
            { 
                colorGradTop = value; 
                Invalidate(); 
            }
        }

        [Browsable(true)]
        public Color ColorGradientBottom
        {
            get 
            { 
                return colorGradBottom; 
            }
            set 
            { 
                colorGradBottom = value; 
                Invalidate(); 
            }
        }

        // sposób malowania gradientowego tła:
        // w zależności od tego czy klawisz myszki jest naciśnięty czy puszczony co sygnalizuje flaga down
        // zamieniane są kolory górny i dolny gradientu 
        // został wybrany zdaniem autora najczęściej spotykany rodzaj gradientu - liniowy (Linear) i zmieniający się w kierunku pionowym (Vertical)
        // po namalowaniu tła następuje umieszczenie na buttonie wycentrowanego w pionie i w poziomie tekstu

        void TBtn_Paint(object sender, PaintEventArgs e)
        {
            rect = ClientRectangle;
            if (!down)
            {
                gradient = new LinearGradientBrush(rect, colorGradTop, colorGradBottom, LinearGradientMode.Vertical);
            }
            else
            {
                gradient = new LinearGradientBrush(rect, colorGradBottom, colorGradTop, LinearGradientMode.Vertical);
            }
            e.Graphics.FillRectangle(gradient, rect);
            Size size = TextRenderer.MeasureText(text, Font);
            e.Graphics.DrawString(text, Font, new SolidBrush(ForeColor), new Point((Width - size.Width) / 2, (Height - size.Height) / 2));
        }
    }
}

Przykład użycia zdarzenia Click

using System;
using System.Windows.Forms;

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();

            // w tym miejscu u czytelnika może pojawić się pytanie: skąd się wzięło tBtn1?
            // otóż po umieszczeniu kontrolki jest jej nadawana nazwa (Name) a kolejne umieszczane kontrolki będą się nazywać
            // tBtn2, tBtn3, tBtn4 itd. te nazwy widać w oknie Properties podpowiada je także sam edytor kodu
            // w opinii autora należy je zmieniać odpowiednio do akcji która nastąpi po kliknięciu danego buttona
            // autorowi nie udało się znaleźć prostego rozwiązania mimo prób własnych i poszukiwań w różnych źrodłach w internecie

            tBtn1.Click += new EventHandler(tBtn1_Click);
        }

        void tBtn1_Click(object sender, EventArgs e)
        {
            MessageBox.Show("Hello!");
        }
    }
}

Widok projektu - gradientowe buttony

gradienty.png

Polecane źródła w internecie

Strona CodeProject

Strona DotNetPerls

Strona StackOverflow

0 komentarzy