本篇C#皮肤美化实例将制作一个类似QQ的带光晕的文本框Textbox,还是先看看最终的效果图(和QQ登陆中的输入框效果差不多):
效果说明: 1.实现了水印的效果 2.实现了鼠标移上去的时候周围产生辉光 3.输入前端可以设置图片。
实现辉光效果
整体说明:
前面显示的那个图片我采用的是一个picturebox,当然如果你愿意也可以自己画(后续的“button再探讨”中就采用的是自己画的方式)。图片后面的输入文本框采用的是textbox控件,这样一来就避免了许多绘制textbox的麻烦(我一开始打算自己绘制用户输入的字符的,不过发现不理想)。然后边框和辉光都是画出来的。
具体实现:
先抛开水印不说。最重要的就是重写的OnPaint方法,如下:
protected override void OnPaint(PaintEventArgs e) { Graphics g = e.Graphics; g.InterpolationMode = InterpolationMode.HighQualityBicubic; g.SmoothingMode = SmoothingMode.HighQuality; CalculateSizeAndPosition(); Draw(e.ClipRectangle, e.Graphics); base.OnPaint(e); }
可以看出里面调用了两个方法,做过前面窗体换肤的可能对这个不陌生。就是绘画之前计算好所有的位置大小信息,然后再调用draw画出来。那么这次的calculateSizeAndPosition又做了什么呢?2点!1.判断是否有前端图片需要显示,2.判断是否处于multiline模式。代码如下:
private void CalculateSizeAndPosition() { if (ForeImage != null) { //图片大小固定为16 pic.Height = pic.Width = 16; pic.Top = pic.Left = 3; txt.Width = Width - pic.Width - 12; txt.Location = new Point(16 + 3 + 3, 6); } else { pic.Left = -40; //隐藏图片 txt.Width = Width - 9; txt.Location = new Point(3, 6); } //单行 if (!txt.Multiline) { Height = txt.Height + 9; } else { txt.Height = Height - 9; //如果是多行则设置实际里面的输入文本框的高度 } }
当所有的东西都计算好了,我们就可以安心的拿起我们的画笔竟然绘画了。先画什么?再画什么?请看代码:
private void Draw(Rectangle rectangle, Graphics g) { #region 画背景 using (SolidBrush backgroundBrush = new SolidBrush(Color.White)) { g.FillRectangle(backgroundBrush, 2, 2, this.Width - 5, this.Height -4); } #endregion #region 画阴影(外边框) Color drawShadowColor = _shadowColor; if (!_isFouse) //判断是否获得焦点 { drawShadowColor = Color.Transparent; } using (Pen shadowPen = new Pen(drawShadowColor)) { if (_radius == 0) { g.DrawRectangle(shadowPen, new Rectangle(rectangle.X, rectangle.Y, rectangle.Width - 1, rectangle.Height - 1)); } else { g.DrawPath(shadowPen, DrawHelper.DrawRoundRect(rectangle.X, rectangle.Y, rectangle.Width - 2, rectangle.Height - 1, _radius)); } } #endregion #region 画边框 using (Pen borderPen = new Pen(_borderColor)) { if (_radius == 0) { g.DrawRectangle(borderPen, new Rectangle(rectangle.X + 1, rectangle.Y + 1, rectangle.Width - 3, rectangle.Height - 3)); } else { g.DrawPath(borderPen, DrawHelper.DrawRoundRect(rectangle.X + 1, rectangle.Y + 1, rectangle.Width - 3, rectangle.Height - 2, _radius)); } } #endregion }
在这个方法里面主要画了三个东西,大家看注释也知道了,分别是:背景,边框,辉光。要注意的就是这里面的微小距离要设置好,我也改了好几次才设置正确。在画边框和辉光的时候,因为实现了圆角边框所以要对圆角度进行判断。
现在绘画的方法也做好了,接下来就是出发重绘的事件了。不然它也不会自动帮你绘画啊^_^。显然当鼠标移上去和移出去的时候需要重新绘画。那我们就在下面几个方法中引发重绘事件:
private void TextBoxEx2_MouseEnter(object sender, EventArgs e) { _isFouse = true; this.Invalidate(); } private void TextBoxEx2_MouseLeave(object sender, EventArgs e) { _isFouse = false; this.Invalidate(); }
代码很简单,不解释。
基本上面的做好了,大部分就完成了。下面我们完成水印的功能。至此,textbox美化讲解完毕,希望对你有帮助
实现水印效果
水印我是这样子实现的:当用户离开输入焦点的时候检测当前用户有没有输入字符,如果没有输入则改变输入框的颜色(灰色),然后看起来就像是水印的感觉啦。我们专门写了一个函数来设置水印,如下:
private void SetWaterMark() { if (_waterMark != null && (txt.Text == " " || txt.Text == @" " + WaterMark)) //用户没有输入 { txt.ForeColor = _waterMarkColor; txt.Text = @" " + WaterMark; } else { txt.ForeColor = ForeColor; } }
然后在什么地方调用呢?刚才上面也已经说了当用户离开焦点的时候判断,不过用户获得输入焦点的时候我们还要设置一下,如果当前的文本时水印的话就清空文本等待输入:
private void Txt_GotFocus(object sender, EventArgs e) { if (txt.Text == @" " + WaterMark) { //获得焦点,切换正常文字等待填写 txt.ForeColor = ForeColor; txt.Text = " "; } } private void Txt_LostFocus(object sender, EventArgs e) { SetWaterMark(); }
这里还有一点需要注意的是,在pageload里面我们也需要调用一下setwatermark方法,不然它一开始是不会显示滴!
源代码快照
namespace QLFUI { public partial class TextBoxEx : UserControl { #region - 变量 - private Color _borderColor = Color.FromArgb(166, 208, 226); private Color _shadowColor = Color.FromArgb(175, 212, 228); private Image _foreImage = null; private bool _isFouse = false; private Color _backColor = Color.Transparent; private string _waterMark = null; private Color _waterMarkColor = Color.Silver; private Color _foreColor = Color.Black; private int _radius = 3; #endregion #region - 属性 - [Category("QLFUI"), Description("边框颜色,BorderStyle为FixedSingle有效")] public Color BorderColor { get { return _borderColor; } set { _borderColor = value; this.Invalidate(); } } [Category("QLFUI"), Description("边框阴影颜色,BorderStyle为FixedSingle有效")] public Color ShadowColor { get { return _shadowColor; } set { _shadowColor = value; this.Invalidate(); } } [Category("QLFUI"), Description("显示的前端的图片")] public Image ForeImage { get { return pic.Image; } set { _foreImage = value; pic.Image = _foreImage; Invalidate(); } } [Category("QLFUI"), Description("文字")] public string Caption { get { return txt.Text; } set { txt.Text = value; SetWaterMark(); Invalidate(); } } [Category("行为"), Description("是否多行显示")] public bool Multiline { get { return txt.Multiline; } set { txt.Multiline = value; } } [Category("行为"), Description("是否以密码形式显示字符")] public bool UseSystemPasswordChar { get { return txt.UseSystemPasswordChar; } set { txt.UseSystemPasswordChar = value; } } [Category("QLFUI"), Description("水印文字")] public string WaterMark { get { return _waterMark; } set { _waterMark = value; Invalidate(); } } [Category("QLFUI"), Description("水印颜色")] public Color WaterMarkColor { get { return _waterMarkColor; } set { _waterMarkColor = value; Invalidate(); } } #region 需要被隐藏的属性 [Browsable(false)] public new BorderStyle BorderStyle { get { return BorderStyle.None; } } [Browsable(false)] public new Color BackColor { get { return base.BackColor; } set { base.BackColor = value; } } [Browsable(false)] public new Image BackgroundImage { get { return null; } } [Browsable(false)] public new ImageLayout BackgroundImageLayout { get { return base.BackgroundImageLayout; } set { base.BackgroundImageLayout = value; } } #endregion [Category("QLFUI"), Description("边角弯曲的角度(1-10),数值越大越弯曲")] public int Radius { get { return _radius; } set { if (value > 10) { value = 10; } if (value < 0) { value = 0; } _radius = value; this.Invalidate(); } } [Browsable(true)] [Category("外观"), Description("文本颜色")] public new Color ForeColor { get { return _foreColor; } set { _foreColor = value; } } [Browsable(true)] [Category("外观"), Description("鼠标形状")] public new Cursor Cursor { get { return txt.Cursor; } set { txt.Cursor = value; } } [Category("行为"), Description("自动提示方式")] public AutoCompleteMode AutoCompleteMode { get { return txt.AutoCompleteMode; } set { txt.AutoCompleteMode = value; } } [Category("行为"), Description("自动提示类型")] public AutoCompleteSource AutoCompleteSource { get { return txt.AutoCompleteSource; } set { txt.AutoCompleteSource = value; } } #endregion #region - 构造函数 - public TextBoxEx() { SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint, true); InitializeComponent(); BackColor = Color.Transparent; //下面的图片和文本框的大小位置必须设置,否则首次启动时 //会出现莫名其妙的断痕 pic.SizeMode = PictureBoxSizeMode.StretchImage; pic.BorderStyle = BorderStyle.None; pic.Height = pic.Width = 16;//图片大小固定为16 pic.Left = -40; //隐藏图片 txt.Width = Width - 9; txt.Location = new Point(3, 6); txt.MouseEnter += new EventHandler(TextBoxEx2_MouseEnter); txt.MouseLeave += new EventHandler(TextBoxEx2_MouseLeave); pic.MouseEnter += new EventHandler(TextBoxEx2_MouseEnter); pic.MouseLeave += new EventHandler(TextBoxEx2_MouseLeave); txt.LostFocus += new EventHandler(Txt_LostFocus); txt.GotFocus += new EventHandler(Txt_GotFocus); pic.BackColor = Color.White; //不设置成白色则边框会一同加阴影 } #endregion #region - 事件 - private void TextBoxEx_Load(object sender, EventArgs e) { SetWaterMark(); } private void TextBoxEx2_MouseEnter(object sender, EventArgs e) { _isFouse = true; this.Invalidate(); } private void TextBoxEx2_MouseLeave(object sender, EventArgs e) { _isFouse = false; this.Invalidate(); } private void Txt_GotFocus(object sender, EventArgs e) { if (txt.Text == @" " + WaterMark) { //获得焦点,切换正常文字等待填写 txt.ForeColor = ForeColor; txt.Text = " "; } } private void Txt_LostFocus(object sender, EventArgs e) { SetWaterMark(); } protected override void OnPaint(PaintEventArgs e) { Graphics g = e.Graphics; g.InterpolationMode = InterpolationMode.HighQualityBicubic; g.SmoothingMode = SmoothingMode.HighQuality; CalculateSizeAndPosition(); Draw(e.ClipRectangle, e.Graphics); base.OnPaint(e); } #endregion #region - 帮助方法 - private void SetWaterMark() { if (_waterMark != null && (txt.Text == " " || txt.Text == @" " + WaterMark)) //用户没有输入 { txt.ForeColor = _waterMarkColor; txt.Text = @" " + WaterMark; } else { txt.ForeColor = ForeColor; } } private void CalculateSizeAndPosition() { if (ForeImage != null) { pic.Top = pic.Left = 3; txt.Width = Width - pic.Width - 12; txt.Location = new Point(16 + 3 + 3, 6); } else { pic.Left = -40; //隐藏图片 txt.Width = Width - 9; txt.Location = new Point(3, 6); } //单行 if (!txt.Multiline) { Height = txt.Height + 9; } else { txt.Height = Height - 9; } } private void Draw(Rectangle rectangle, Graphics g) { #region 画背景 using (SolidBrush backgroundBrush = new SolidBrush(Color.White)) { g.FillRectangle(backgroundBrush, 2, 2, this.Width - 5, this.Height -4); } #endregion #region 画阴影(外边框) Color drawShadowColor = _shadowColor; if (!_isFouse) //判断是否获得焦点 { drawShadowColor = Color.Transparent; } using (Pen shadowPen = new Pen(drawShadowColor)) { if (_radius == 0) { g.DrawRectangle(shadowPen, new Rectangle(rectangle.X, rectangle.Y, rectangle.Width - 1, rectangle.Height - 1)); } else { g.DrawPath(shadowPen, DrawHelper.DrawRoundRect(rectangle.X, rectangle.Y, rectangle.Width - 2, rectangle.Height - 1, _radius)); } } #endregion #region 画边框 using (Pen borderPen = new Pen(_borderColor)) { if (_radius == 0) { g.DrawRectangle(borderPen, new Rectangle(rectangle.X + 1, rectangle.Y + 1, rectangle.Width - 3, rectangle.Height - 3)); } else { g.DrawPath(borderPen, DrawHelper.DrawRoundRect(rectangle.X + 1, rectangle.Y + 1, rectangle.Width - 3, rectangle.Height - 2, _radius)); } } #endregion } #endregion } }