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 重绘消息,只要模式对话框显示即可。

您的代码创建:

如您所见,该按钮在制表位上绘制了两种不同的效果。 hoverfocus 效果。虽然它绘制 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 StringFormatGraphics.DrawString(..) 方法一起传递)来指示与其他文本布局一起信息。
  • 不要忘记处理图形对象(代码中的 pen1 和 pen2)。