Reputation:
I am new to Custom Controls. I'm trying to create a flat Button
which changes its border color and text color when the Mouse or the Keyboard focus comes to it.
When I change the BorderColor
Property of the Button
from the Designer, it doesn't update the color and also when I run the program, BorderColor
remains the same.
I am not sure about the OnPaint()
event code I have written. It consoles out twice when run first time. I don't know why!
How to make a Custom Control so its attributes can be fiddled in Designer?
using System;
using System.Drawing;
using System.Windows.Forms;
namespace Mato
{
class FlatButton : Control
{
public override Cursor Cursor { get; set; } = Cursors.Hand;
public float BorderThickness { get; set; } = 2;
public Color BorderColor { get; set; } = ColorTranslator.FromHtml("#0047A0");
public Color TextColor { get; set; } = ColorTranslator.FromHtml("#0047A0");
public Color ActiveBorderColor { get; set; } = ColorTranslator.FromHtml("#158C3F");
public Color ActiveTextColor { get; set; } = ColorTranslator.FromHtml("#158C3F");
private SolidBrush borderBrush, textBrush;
private Rectangle borderRectangle;
private bool active = false;
private StringFormat stringFormat = new StringFormat();
public FlatButton()
{
borderBrush = new SolidBrush(BorderColor);
textBrush = new SolidBrush(TextColor);
stringFormat.Alignment = StringAlignment.Center;
stringFormat.LineAlignment = StringAlignment.Center;
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
Console.WriteLine(textBrush.Color.ToString());
borderRectangle = new Rectangle(0, 0, Width, Height);
e.Graphics.DrawRectangle(new Pen(borderBrush, BorderThickness), borderRectangle);
e.Graphics.DrawString(this.Text, this.Font, (active) ? textBrush : borderBrush, borderRectangle, stringFormat);
}
protected override void OnMouseDown(MouseEventArgs e)
{
textBrush.Color = ActiveTextColor;
this.Refresh();
active = true;
base.OnMouseDown(e);
}
protected override void OnMouseUp(MouseEventArgs e)
{
textBrush.Color = TextColor;
this.Refresh();
active = false;
base.OnMouseUp(e);
}
protected override void OnGotFocus(EventArgs e)
{
//MessageBox.Show("Focused");
borderBrush.Color = ActiveBorderColor;
textBrush.Color = ActiveTextColor;
this.Refresh();
active = true;
base.OnGotFocus(e);
}
protected override void OnLostFocus(EventArgs e)
{
borderBrush.Color = BorderColor;
textBrush.Color = TextColor;
this.Refresh();
active = false;
base.OnLostFocus(e);
}
}
}
Upvotes: 2
Views: 252
Reputation: 32288
I slightly modified your original class, adding some private fields that keep track of the current status of your Button control.
Substituted: OnGotFocus()
and OnLostFocus()
with OnEnter()
and OnLeave()
Added some private fields that reference the current Color of Text and Border, when those are modified on a Button Click() event and when the Control is entered or when the input focus leaves.
private Color m_CurrentBorderColor;
private Color m_CurrentTextColor;
Also, each time a property is changed, the Invalidate()
method is called, which raises the OnPaint() event of the Control, updating its aspect.
Other minor changes.
class FlatButton : Control
{
private Color m_TextColor;
private Color m_BorderColor;
private Color m_ActiveBorderColor;
private Color m_ActiveTextColor;
private Color m_CurrentBorderColor;
private Color m_CurrentTextColor;
public override Cursor Cursor { get; set; } = Cursors.Hand;
public float BorderThickness { get; set; } = 2;
public Color BorderColor {
get => this.m_BorderColor;
set { this.m_BorderColor = value;
this.m_CurrentBorderColor = value;
this.Invalidate();
}
}
public Color TextColor {
get => this.m_TextColor;
set {
this.m_TextColor = value;
this.m_CurrentTextColor = value;
this.Invalidate();
}
}
public Color ActiveBorderColor { get => this.m_ActiveBorderColor; set { this.m_ActiveBorderColor = value; } }
public Color ActiveTextColor { get => this.m_ActiveTextColor; set { this.m_ActiveTextColor = value; } }
private StringFormat stringFormat;
public FlatButton()
{
this.m_TextColor = ColorTranslator.FromHtml("#0047A0");
this.m_BorderColor = ColorTranslator.FromHtml("#0047A0");
this.m_ActiveBorderColor = ColorTranslator.FromHtml("#158C3F");
this.m_ActiveTextColor = ColorTranslator.FromHtml("#158C3F");
this.m_CurrentTextColor = this.m_TextColor;
this.m_CurrentBorderColor = this.m_BorderColor;
stringFormat = new StringFormat()
{
Alignment = StringAlignment.Center,
LineAlignment = StringAlignment.Center
};
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
using (SolidBrush textBrush = new SolidBrush(this.m_CurrentTextColor))
using (Pen pen = new Pen(this.m_CurrentBorderColor, this.BorderThickness))
{
e.Graphics.DrawRectangle(pen, e.ClipRectangle);
e.Graphics.DrawString(this.Text, this.Font, textBrush, e.ClipRectangle, stringFormat);
}
}
protected override void OnMouseDown(MouseEventArgs e)
{
base.OnMouseDown(e);
this.m_CurrentTextColor = this.m_ActiveTextColor;
this.Invalidate();
}
protected override void OnMouseUp(MouseEventArgs e)
{
base.OnMouseUp(e);
this.m_CurrentTextColor = this.m_TextColor;
this.Invalidate();
}
protected override void OnEnter(EventArgs e)
{
base.OnEnter(e);
this.m_CurrentBorderColor = this.m_ActiveBorderColor;
this.m_CurrentTextColor = this.m_ActiveTextColor;
this.Invalidate();
}
protected override void OnLeave(EventArgs e)
{
base.OnLeave(e);
this.m_CurrentBorderColor = this.m_TextColor;
this.m_CurrentTextColor = this.m_BorderColor;
this.Invalidate();
}
}
Upvotes: 1