5.处理自定义控件焦点
Posted crystal_lz
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了5.处理自定义控件焦点相关的知识,希望对你有一定的参考价值。
5.处理自定义控件焦点
原文请看:http://www.clzf.co/blog.php其实要说啥是焦点 从口头上来说 我也不知道应该怎么描述 如果非要我描述一下的话 我也只能说:获得焦点的控件会接受用户的键盘事件
比如说 窗体上有两个文本框 我在上面一个文本框打字的时候 不会打到下面的一个文本框里面去 因为在那个时候 具有焦点的是 上面的一个文本框 相信平时 有看到这样的效果像这样的虚线框 表示此刻button2具有焦点 如果这个时候按下回车或者空格的话 就等同于点击了button2 而按下键盘上的Tab键会在窗体上的控件之间切换焦点、、而获得焦点的控件会变成什么样子的长相 这个得由控件自己去处理
假设就这样创建一个自定义控件放到窗体上 然后按下Tab把焦点切换到控件上去 是看不到任何效果的:
此时此刻 焦点在我的自定义控件上(为了方便显示 我设置成了红色) 还有 如果你在控件的单击事件里面写上一些代码 你按下 回车或者空格 你也是看不到啥效果的:
private void focusControl1_Click(object sender, EventArgs e)
MessageBox.Show("Focus");
虽然此刻 自定义控件获得了焦点 但不代表你此时此刻按下回车或者空格 就会自动的去触发单击事件 这个得自己写代码实现
现在先来绘制控件 让他得到焦点的时候能有点不同:
protected override void OnPaint(PaintEventArgs e)
Graphics g = e.Graphics;
if (this.Focused && this.ShowFocusCues/* this.ContainsFocus */)
using (Pen p = new Pen(Color.Gray))
p.DashStyle = System.Drawing.Drawing2D.DashStyle.Dot;
g.DrawRectangle(p, 2, 2, this.Width - 5, this.Height - 5);
g.DrawRectangle(Pens.DarkCyan, 0, 0, this.Width - 1, this.Height - 1);
base.OnPaint(e);
override OnPaint就不多说了其实也没有啥 看上去就是比起以前 在里面加入了一个判断而已 判断当前是否得到焦点 注意 可以看到的是判断里面我注释了一个 一般情况下两者你都可以用 而他们的区别就是:
- ContainsFocus:是否包涵有焦点 也就是如果说控件还有子控件 无论是自身得到焦点还是子控件得到焦点 都是true
- Focused:不会去管子控件是否包涵有焦点
- 注:其实这两者的区别我也是看资料上说的 并没有实际的实践过
ShowFocusCues 决定是否显示焦点框、、什么意思 意思就是默认情况下 窗体上是不会显示焦点框的 不信你试试新建一个窗体 上面搞几个button出来是时候 你去点击那些button看看有没有焦点框?或许被你点击过的按钮是高亮显示的 但是没有焦点框 不过如果这个时候 你点下过Tab来切换焦点 那么控件上面就会显示焦点框了 这个属性的值是只读的 由系统来觉得当前是否应该显示焦点框
但是这样写你运行的时候可能会发现 按下Tab把焦点切换到控件上面去的时候 没有出现什么反映 这里在前面的时候就已经说过了 Paint 只会在得到通知绘制的时候才会执行 而当控件得到或者失去焦点的时候没有去通知 Paint 事件绘制 所以得自己去处理
很简单有两个事件 GotFocus 和 LostFocus 在这两个事件里面通知重绘就可以了(注:这两个事件是在属性窗口找不到的 不只是自定义控件是这样的 其他控件也是 但是可以通过 点 出来)
public FocusControl()
this.GotFocus += (s, e) => this.Invalidate();
this.LostFocus += (s, e) => this.Invalidate();
//protected override void OnGotFocus(EventArgs e)
// this.Invalidate();
// base.OnGotFocus(e);
//
//protected override void OnLostFocus(EventArgs e)
// this.Invalidate();
// base.OnLostFocus(e);
//
像上面一样 你可以选择override也可以选择像我上面那样 更具个人喜好 反正就是处理这两个事件为目的 处理的方式很多 选择自己喜欢的就可以了 通常情况下 要是代码不多 我就会选择像上面的一种写法 如果你不知道上面的那个写法是啥 请百度"匿名委托" 这样当焦点离开 或者得到焦点的时候 就能看到变化了:
(- -! 不要嫌弃好丑 这一篇只讲焦点 所以为了代码简洁 就暂时不添加其他代码)
注:在[GDI+程序设计]一书中 是用的ChangeUICues事件来搞的 但是当时我用了却没有效果 所以就用的Got/LostFocus事件
但是 就这样看上去是没有啥问题了 其实还有bug 比如 假设现在焦点在button1上 而此时我点击自定义控件 控件也执行了Click事件 但是焦点还是在button1上面 现在反过来看看 加入焦点现在在自定义控件上 如果此时我去点击button1可以发现button1得到了焦点 而自定义控件失去了焦点 所以还得处理自定义控件的点击 使他点击的时候得到焦点 可能这个时候你会想到处理控件的Click事件 在里面让他得到焦点 确实 不过还是建议处理MouseDown事件 仔细看看 当焦点在自定义控件的时候 点击button1 是不是点下去 鼠标还没有抬起来的时候 button1就已经得到了焦点了?(注:Click = MouseDown + MouseUp)
所以再加代码:
protected override void OnMouseDown(MouseEventArgs e)
this.Focus();
base.OnMouseDown(e);
或者构造器中:
this.MouseDown += (s,e) => this.Invalidate();
到此 焦点切换基本就没啥问题了
现在来处理一下按键 让它能像button那样得到焦点时 按下回车或者空格 就会触发Click事件 那么处理一下KeyDown事件:
protected override void OnKeyDown(KeyEventArgs e)
if (e.Modifiers == Keys.None && (e.KeyCode == Keys.Space || e.KeyCode == Keys.Enter))
this.OnClick(new EventArgs());
base.OnKeyDown(e);
那个Modifiers是指 有没有按下Ctrl或者Alt或者Shift 如果没有按下任意一个 并且按下了回车或者空格 那么调用一下控件的单击事件 这个时候 最上面的时候写在控件Click事件里面的提示框也会弹出来了
对于 焦点 这里就讲这么多 其实一个控件不只是有焦点和无焦点的状态 比如还有Enable Enable的状态就不打算单独讲了 因为和上面一样只是在Paint里面多一个判断而已 控件禁用时候张什么样子 绘制就是了 不过不同的是 不用像上面的Got/LostFocus那样去通知Paint 当Enable的值发生变化的时候 会自己执行Paint 所以可以直接在Paint里面判断就行了比如:
protected override void OnPaint(PaintEventArgs e)
Graphics g = e.Graphics;
if (!this.Enabled)
g.FillRectangle(Brushes.Gray, this.ClientRectangle);
else
if (this.Focused && this.ShowFocusCues/* this.ContainsFocus */)
using (Pen p = new Pen(Color.Gray))
p.DashStyle = System.Drawing.Drawing2D.DashStyle.Dot;
g.DrawRectangle(p, 2, 2, this.Width - 5, this.Height - 5);
g.DrawRectangle(Pens.DarkCyan, 0, 0, this.Width - 1, this.Height - 1);
base.OnPaint(e);
如果控件禁用的时候 我填充一整块灰色(只是演示而已 禁用的时候要张什么样子你想怎么画 怎么画) 否则正常绘制
至于 焦点 为什么要单独列出来说 是因为焦点扯到的东西比较多 如上面Enable的和焦点的比较 焦点不只是在Paint里面来个判断而已 还要扯到其他的 所以单独列了出来、、在下一篇中 再讲解一下热键就基本差不多了 然后综合前几篇的文章 来个小练习、、然后继续讲一些关于在窗体设计器时候的一些东西..<
以上是关于5.处理自定义控件焦点的主要内容,如果未能解决你的问题,请参考以下文章