Gradientowy PushButton
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!");
}
}
}