【问题标题】:How to call Paint event on MouseHover?如何在鼠标悬停时调用 Paint 事件?
【发布时间】:2018-08-08 10:35:01
【问题描述】:

我有一个面板的 Paint 事件,它在面板周围绘制一个矩形以突出显示它。

绘画活动-

 private void deal_details_panel_Paint(object sender, PaintEventArgs e)
        {
          int thickness = 2;//it's up to you
            int halfThickness = thickness / 2;
            using (Pen p = new Pen(Color.GreenYellow, thickness))
            {
                e.Graphics.DrawRectangle(p, new Rectangle(halfThickness,
                                                          halfThickness,
                                                          deal_details_panel.ClientSize.Width - thickness,
                                                          deal_details_panel.ClientSize.Height - thickness));
            }

        }

最初我不想显示这个矩形,我有一个按钮,如果我将鼠标悬停在该按钮上,然后我想显示这个矩形,并且在 MouseLeave 事件上我想让它再次不可见。

Button_Hover-

private void add_MouseHover(object sender, EventArgs e)
        {



            deal_details_panel.Invalidate();



        }

我看到了一些使用 Invalidate() 的答案,但是 Invalidate() 对我不起作用。

【问题讨论】:

    标签: c# visual-studio winforms


    【解决方案1】:

    使用Refresh() 而不是Invalidate()

    Invalidate() 方法不会强制重新绘制,它只是将控件标记为“需要重新绘制”,让操作系统在需要时重新绘制。

    Refresh() 方法将立即强制重新绘制。

    有关更多信息,请阅读 Whats the difference between Control.Invalidate, Control.Update and Control.Refresh? 博客文章,其中明确指出:

    Control.Invalidate( ) / Control.Invalidate(bool) / Control.Invalidate(Rectangle) / Control.Invalidate(Rectangle, bool) / Control.Invalidate(Region) / Control.Invalidate(Region, bool) …… 这里要注意的重要一点是,这些函数只是通过将客户区添加到控件窗口的当前更新区域来“无效”或“弄脏”客户区。当接收到下一个 WM_PAINT 消息时,该无效区域以及更新区域中的所有其他区域都被标记为绘制。因此,您可能不会立即(或同步)看到您的控件刷新(并显示失效)。

    更新

    为了让面板仅在鼠标悬停在按钮上时显示 YellowGreen 边框,您需要稍微更改代码。

    首先,在你的表单中添加一个bool字段,表示是否绘制边框,初始化为false:

    private bool _drawBorder = false;
    

    然后,更改paint 方法以考虑该值:

    private void deal_details_panel_Paint(object sender, PaintEventArgs e)
    {
        if(_drawBorder)
        {
            int thickness = 2;//it's up to you
            int halfThickness = thickness / 2;
            using (Pen p = new Pen(Color.GreenYellow, thickness))
            {
                e.Graphics.DrawRectangle(p, new Rectangle(halfThickness,
                                                          halfThickness,
                                                          deal_details_panel.ClientSize.Width - thickness,
                                                          deal_details_panel.ClientSize.Height - thickness));
            }
        }
    }
    

    最后,不要在按钮上使用 mouse_Hover 事件,而是使用 MouseEnterMouseLeave
    这有两个原因 - 1:Mouse_Hover 具有内置延迟和 2:使用 Mouse_Hover 当鼠标停止悬停在按钮上时,您不会得到指示。

    MouseEnterMouseLeave 事件处理程序中,您只需更新_drawBorder 的值并调用deal_details_panel.Refresh()

    private void add_MouseEnter(object sender, EventArgs e)
    {
        _drawBorder = true;
        deal_details_panel.Refresh();
    }
    
    private void add_MouseLeave(object sender, EventArgs e)
    {
        _drawBorder = false;
        deal_details_panel.Refresh();
    }
    

    【讨论】:

    • 我试过了,但我不想在应用程序启动后立即显示绿色矩形。我只想在我将鼠标悬停在按钮上时显示它。
    • 这是因为每当控件被绘制时都会调用该方法。您需要在您的类中添加一个用作标志的字段,以便您可以在绘制方法内部知道鼠标是否悬停在按钮上,并决定是否要相应地绘制边框。
    • 您能告诉我一种方法吗?我是 Winform 应用程序开发的新手。我可以使用 bool 来检查条件,但如何检查鼠标悬停在按钮上?
    • 非常感谢!我只是在 add_MouseEnter 中将 _drawBorder 值更改为 false,在 add_Mouseleave 中更改为 True。现在它就像一个魅力! :)
    【解决方案2】:

    Zohar 指出了正确的解决方案,但我会添加一个更改建议:

    using (Pen p = new Pen(Color.GreenYellow, thickness))
    

    到:

    using (Pen p = new Pen(Color.Transparent, thickness))
    

    这将从一开始就设置正确的状态,因此无需重新绘制。

    【讨论】:

      猜你喜欢
      • 2016-08-08
      • 2018-08-13
      • 2011-03-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多