C# 检查控件的父控件是否失去焦点
C# Check if control's parent lost focus
我有一个自定义控件,一个悬停按钮,只要鼠标移到它上面或获得焦点,它就会显示边框。
一切正常,但我在处理以下情况时遇到问题:我单击按钮并显示另一种形式 (ShowDialog) 或 (MessageBox),然后 return 返回父形式控件。
这是控制代码:
namespace CustomControlTutorial
{
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
public partial class HoverButton : Button
{
byte eventPaintMode = 0;
//Color borderClr = Color.Transparent;
public HoverButton()
{
InitializeComponent();
}
protected override void OnPaint(PaintEventArgs pe)
{
//base.OnPaint(pe);
// render background
Color clr = this.Parent.BackColor;
Brush b = new SolidBrush(clr);
pe.Graphics.FillRectangle(b, ClientRectangle);
// Draw borders depending on event case
Point p00 = new Point(0, 0);
Point p01 = new Point(0, ClientSize.Height - 1);
Point p10 = new Point(ClientSize.Width - 1, 0);
Point p11 = new Point(ClientSize.Width - 1, ClientSize.Height - 1);
Pen pen1;
Pen pen2;
switch (eventPaintMode)
{
case 1:
{
// draw borders (using pen)
pen1 = new Pen(new SolidBrush(Color.DimGray), 1);
pen2 = new Pen(new SolidBrush(Color.White), 1);
pe.Graphics.DrawLine(pen1, p10, p11);
pe.Graphics.DrawLine(pen2, p00, p10);
pe.Graphics.DrawLine(pen1, p01, p11);
pe.Graphics.DrawLine(pen2, p00, p01);
break;
}
case 2:
{
pen2 = new Pen(new SolidBrush(Color.DimGray), 1);
pen1 = new Pen(new SolidBrush(Color.White), 1);
pe.Graphics.DrawLine(pen1, p10, p11);
pe.Graphics.DrawLine(pen2, p00, p10);
pe.Graphics.DrawLine(pen1, p01, p11);
pe.Graphics.DrawLine(pen2, p00, p01);
break;
}
case 3:
{
// draw borders (using pen)
pen1 = new Pen(new SolidBrush(Color.DimGray), 1);
pen2 = new Pen(new SolidBrush(Color.White), 1);
pe.Graphics.DrawLine(pen1, p10, p11);
pe.Graphics.DrawLine(pen2, p00, p10);
pe.Graphics.DrawLine(pen1, p01, p11);
pe.Graphics.DrawLine(pen2, p00, p01);
// draw focus lines
pen1 = new Pen(new SolidBrush(Color.Black), 1);
pen1.DashCap = DashCap.Round;
pen1.DashPattern = new float[] { 1, 1, 1, 1 };
p00 = new Point(5, 5);
p01 = new Point(5, ClientSize.Height - 6);
p10 = new Point(ClientSize.Width - 6, 5);
p11 = new Point(ClientSize.Width - 6, ClientSize.Height - 6);
pe.Graphics.DrawLine(pen1, p10, p11);
pe.Graphics.DrawLine(pen1, p00, p10);
pe.Graphics.DrawLine(pen1, p01, p11);
pe.Graphics.DrawLine(pen1, p00, p01);
pe.Graphics.SmoothingMode = SmoothingMode.None;
break;
}
default:
break;
}
// render text
String drawString = this.Text;
SizeF size = pe.Graphics.MeasureString(drawString, this.Font);
float pointX = ((float)ClientSize.Width - size.Width) / 2;
float pointY = ((float)ClientSize.Height - size.Height) / 2;
pe.Graphics.DrawString(Text, Font, new SolidBrush(ForeColor), (int)pointX, (int)pointY);
b.Dispose();
}
protected override void OnMouseEnter(EventArgs e)
{
base.OnMouseEnter(e);
eventPaintMode = 1;
Invalidate();
}
protected override void OnMouseLeave(EventArgs e)
{
base.OnMouseLeave(e);
eventPaintMode = 0;
Invalidate();
}
protected override void OnMouseDown(MouseEventArgs e)
{
base.OnMouseDown(e);
if (e.Button == MouseButtons.Left)
{
eventPaintMode = 2;
Invalidate();
}
}
protected override void OnMouseUp(MouseEventArgs e)
{
base.OnMouseUp(e);
if (e.Button == MouseButtons.Left)
{
eventPaintMode = 1;
Invalidate();
}
}
protected override void OnGotFocus(EventArgs e)
{
base.OnGotFocus(e);
eventPaintMode = 3;
Invalidate();
}
protected override void OnLostFocus(EventArgs e)
{
base.OnLostFocus(e);
eventPaintMode = 0;
Invalidate();
}
}
}
这是我显示测试消息框的地方:
private void hoverButton1_Click(object sender, EventArgs e)
{
MessageBox.Show("Test");
}
我找不到类似 OnParentLostFocus 之类的事件。
The problem is that when I set the button to show a message, the button's parent (Form) can't be accessed until the message is closed. So there is no connection between the 2 forms that I can use to make any changes to the button..
这就是它的工作原理。 parent From 及其子级不会收到 windows 重绘消息,只要模式对话框显示即可。
您的代码创建:
如您所见,该按钮在制表位上绘制了两种不同的效果。 hover 和 focus 效果。虽然它绘制 hover 效果并忽略 focus 上的 MouseEnter
效果,即使控件当前具有焦点。另一件事是,当模式对话框关闭时,按钮不显示或绘制 normal/default 状态。
恕我直言,两者不应结合,与鼠标事件交互以绘制悬停和向下效果,并在控件获得焦点且未应用鼠标效果时绘制焦点矩形。就像默认 System.Windows.Forms.Button
的工作方式一样。
例如:
// Your namespace...
public enum MouseState : int
{
None, Over, Down
}
[DesignerCategory("Code")]
public class HoverButton : Button
{
private MouseState state = MouseState.None;
public HoverButton() : base()
{
SetStyle(
ControlStyles.AllPaintingInWmPaint |
ControlStyles.UserPaint |
ControlStyles.ResizeRedraw, true);
UpdateStyles();
}
protected override void OnPaint(PaintEventArgs e)
{
var g = e.Graphics;
var r = ClientRectangle;
g.Clear(Parent.BackColor);
var p00 = new Point(0, 0);
var p01 = new Point(0, r.Height - 1);
var p10 = new Point(r.Width - 1, 0);
var p11 = new Point(r.Width - 1, r.Height - 1);
switch (state)
{
case MouseState.Over:
if (r.Contains(PointToClient(MousePosition)))
{
g.DrawLine(Pens.DimGray, p10, p11);
g.DrawLine(Pens.White, p00, p10);
g.DrawLine(Pens.DimGray, p01, p11);
g.DrawLine(Pens.White, p00, p01);
}
break;
case MouseState.Down:
g.DrawLine(Pens.White, p10, p11);
g.DrawLine(Pens.DimGray, p00, p10);
g.DrawLine(Pens.White, p01, p11);
g.DrawLine(Pens.DimGray, p00, p01);
break;
default:
break;
}
TextRenderer.DrawText(g, Text, Font, r, ForeColor,
TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter);
if (Focused && MouseButtons == MouseButtons.None &&
!r.Contains(PointToClient(MousePosition)))
{
r.Inflate(-2, -2);
ControlPaint.DrawFocusRectangle(g, r);
}
}
protected override void OnMouseEnter(EventArgs e)
{
base.OnMouseEnter(e);
state = MouseState.Over;
Invalidate();
}
protected override void OnMouseLeave(EventArgs e)
{
base.OnMouseLeave(e);
state = MouseState.None;
Invalidate();
}
protected override void OnMouseDown(MouseEventArgs e)
{
base.OnMouseDown(e);
if (e.Button == MouseButtons.Left)
{
state = MouseState.Down;
Invalidate();
}
}
protected override void OnMouseUp(MouseEventArgs e)
{
base.OnMouseUp(e);
state = MouseState.Over;
Invalidate();
}
protected override void OnEnter(EventArgs e)
{
base.OnEnter(e);
state = MouseState.None;
Invalidate();
}
protected override void OnLeave(EventArgs e)
{
base.OnLeave(e);
state = MouseState.None;
Invalidate();
}
}
创建:
旁注
- 调用
e.Graphics.Clear(..)
方法用所需的颜色清除绘图canvas。
- 尽可能使用预定义的 Brushes and Pens 而不是创建新的图形对象。
- TextRenderer 是在控件上绘制字符串的更好选择,而
e.Graphics.DrawString(..)
是在图像上绘制的更好选择。
- 要使文本在控件中居中,将其绘制在一个矩形中并使用重载,您可以在其中将 TextFormatFlags (or the StringFormat 与
Graphics.DrawString(..)
方法一起传递)来指示与其他文本布局一起信息。
- 不要忘记处理图形对象(代码中的 pen1 和 pen2)。
我有一个自定义控件,一个悬停按钮,只要鼠标移到它上面或获得焦点,它就会显示边框。
一切正常,但我在处理以下情况时遇到问题:我单击按钮并显示另一种形式 (ShowDialog) 或 (MessageBox),然后 return 返回父形式控件。
这是控制代码:
namespace CustomControlTutorial
{
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
public partial class HoverButton : Button
{
byte eventPaintMode = 0;
//Color borderClr = Color.Transparent;
public HoverButton()
{
InitializeComponent();
}
protected override void OnPaint(PaintEventArgs pe)
{
//base.OnPaint(pe);
// render background
Color clr = this.Parent.BackColor;
Brush b = new SolidBrush(clr);
pe.Graphics.FillRectangle(b, ClientRectangle);
// Draw borders depending on event case
Point p00 = new Point(0, 0);
Point p01 = new Point(0, ClientSize.Height - 1);
Point p10 = new Point(ClientSize.Width - 1, 0);
Point p11 = new Point(ClientSize.Width - 1, ClientSize.Height - 1);
Pen pen1;
Pen pen2;
switch (eventPaintMode)
{
case 1:
{
// draw borders (using pen)
pen1 = new Pen(new SolidBrush(Color.DimGray), 1);
pen2 = new Pen(new SolidBrush(Color.White), 1);
pe.Graphics.DrawLine(pen1, p10, p11);
pe.Graphics.DrawLine(pen2, p00, p10);
pe.Graphics.DrawLine(pen1, p01, p11);
pe.Graphics.DrawLine(pen2, p00, p01);
break;
}
case 2:
{
pen2 = new Pen(new SolidBrush(Color.DimGray), 1);
pen1 = new Pen(new SolidBrush(Color.White), 1);
pe.Graphics.DrawLine(pen1, p10, p11);
pe.Graphics.DrawLine(pen2, p00, p10);
pe.Graphics.DrawLine(pen1, p01, p11);
pe.Graphics.DrawLine(pen2, p00, p01);
break;
}
case 3:
{
// draw borders (using pen)
pen1 = new Pen(new SolidBrush(Color.DimGray), 1);
pen2 = new Pen(new SolidBrush(Color.White), 1);
pe.Graphics.DrawLine(pen1, p10, p11);
pe.Graphics.DrawLine(pen2, p00, p10);
pe.Graphics.DrawLine(pen1, p01, p11);
pe.Graphics.DrawLine(pen2, p00, p01);
// draw focus lines
pen1 = new Pen(new SolidBrush(Color.Black), 1);
pen1.DashCap = DashCap.Round;
pen1.DashPattern = new float[] { 1, 1, 1, 1 };
p00 = new Point(5, 5);
p01 = new Point(5, ClientSize.Height - 6);
p10 = new Point(ClientSize.Width - 6, 5);
p11 = new Point(ClientSize.Width - 6, ClientSize.Height - 6);
pe.Graphics.DrawLine(pen1, p10, p11);
pe.Graphics.DrawLine(pen1, p00, p10);
pe.Graphics.DrawLine(pen1, p01, p11);
pe.Graphics.DrawLine(pen1, p00, p01);
pe.Graphics.SmoothingMode = SmoothingMode.None;
break;
}
default:
break;
}
// render text
String drawString = this.Text;
SizeF size = pe.Graphics.MeasureString(drawString, this.Font);
float pointX = ((float)ClientSize.Width - size.Width) / 2;
float pointY = ((float)ClientSize.Height - size.Height) / 2;
pe.Graphics.DrawString(Text, Font, new SolidBrush(ForeColor), (int)pointX, (int)pointY);
b.Dispose();
}
protected override void OnMouseEnter(EventArgs e)
{
base.OnMouseEnter(e);
eventPaintMode = 1;
Invalidate();
}
protected override void OnMouseLeave(EventArgs e)
{
base.OnMouseLeave(e);
eventPaintMode = 0;
Invalidate();
}
protected override void OnMouseDown(MouseEventArgs e)
{
base.OnMouseDown(e);
if (e.Button == MouseButtons.Left)
{
eventPaintMode = 2;
Invalidate();
}
}
protected override void OnMouseUp(MouseEventArgs e)
{
base.OnMouseUp(e);
if (e.Button == MouseButtons.Left)
{
eventPaintMode = 1;
Invalidate();
}
}
protected override void OnGotFocus(EventArgs e)
{
base.OnGotFocus(e);
eventPaintMode = 3;
Invalidate();
}
protected override void OnLostFocus(EventArgs e)
{
base.OnLostFocus(e);
eventPaintMode = 0;
Invalidate();
}
}
}
这是我显示测试消息框的地方:
private void hoverButton1_Click(object sender, EventArgs e)
{
MessageBox.Show("Test");
}
我找不到类似 OnParentLostFocus 之类的事件。
The problem is that when I set the button to show a message, the button's parent (Form) can't be accessed until the message is closed. So there is no connection between the 2 forms that I can use to make any changes to the button..
这就是它的工作原理。 parent From 及其子级不会收到 windows 重绘消息,只要模式对话框显示即可。
您的代码创建:
如您所见,该按钮在制表位上绘制了两种不同的效果。 hover 和 focus 效果。虽然它绘制 hover 效果并忽略 focus 上的 MouseEnter
效果,即使控件当前具有焦点。另一件事是,当模式对话框关闭时,按钮不显示或绘制 normal/default 状态。
恕我直言,两者不应结合,与鼠标事件交互以绘制悬停和向下效果,并在控件获得焦点且未应用鼠标效果时绘制焦点矩形。就像默认 System.Windows.Forms.Button
的工作方式一样。
例如:
// Your namespace...
public enum MouseState : int
{
None, Over, Down
}
[DesignerCategory("Code")]
public class HoverButton : Button
{
private MouseState state = MouseState.None;
public HoverButton() : base()
{
SetStyle(
ControlStyles.AllPaintingInWmPaint |
ControlStyles.UserPaint |
ControlStyles.ResizeRedraw, true);
UpdateStyles();
}
protected override void OnPaint(PaintEventArgs e)
{
var g = e.Graphics;
var r = ClientRectangle;
g.Clear(Parent.BackColor);
var p00 = new Point(0, 0);
var p01 = new Point(0, r.Height - 1);
var p10 = new Point(r.Width - 1, 0);
var p11 = new Point(r.Width - 1, r.Height - 1);
switch (state)
{
case MouseState.Over:
if (r.Contains(PointToClient(MousePosition)))
{
g.DrawLine(Pens.DimGray, p10, p11);
g.DrawLine(Pens.White, p00, p10);
g.DrawLine(Pens.DimGray, p01, p11);
g.DrawLine(Pens.White, p00, p01);
}
break;
case MouseState.Down:
g.DrawLine(Pens.White, p10, p11);
g.DrawLine(Pens.DimGray, p00, p10);
g.DrawLine(Pens.White, p01, p11);
g.DrawLine(Pens.DimGray, p00, p01);
break;
default:
break;
}
TextRenderer.DrawText(g, Text, Font, r, ForeColor,
TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter);
if (Focused && MouseButtons == MouseButtons.None &&
!r.Contains(PointToClient(MousePosition)))
{
r.Inflate(-2, -2);
ControlPaint.DrawFocusRectangle(g, r);
}
}
protected override void OnMouseEnter(EventArgs e)
{
base.OnMouseEnter(e);
state = MouseState.Over;
Invalidate();
}
protected override void OnMouseLeave(EventArgs e)
{
base.OnMouseLeave(e);
state = MouseState.None;
Invalidate();
}
protected override void OnMouseDown(MouseEventArgs e)
{
base.OnMouseDown(e);
if (e.Button == MouseButtons.Left)
{
state = MouseState.Down;
Invalidate();
}
}
protected override void OnMouseUp(MouseEventArgs e)
{
base.OnMouseUp(e);
state = MouseState.Over;
Invalidate();
}
protected override void OnEnter(EventArgs e)
{
base.OnEnter(e);
state = MouseState.None;
Invalidate();
}
protected override void OnLeave(EventArgs e)
{
base.OnLeave(e);
state = MouseState.None;
Invalidate();
}
}
创建:
旁注
- 调用
e.Graphics.Clear(..)
方法用所需的颜色清除绘图canvas。 - 尽可能使用预定义的 Brushes and Pens 而不是创建新的图形对象。
- TextRenderer 是在控件上绘制字符串的更好选择,而
e.Graphics.DrawString(..)
是在图像上绘制的更好选择。 - 要使文本在控件中居中,将其绘制在一个矩形中并使用重载,您可以在其中将 TextFormatFlags (or the StringFormat 与
Graphics.DrawString(..)
方法一起传递)来指示与其他文本布局一起信息。 - 不要忘记处理图形对象(代码中的 pen1 和 pen2)。