当鼠标不在标题栏上方时隐藏窗体的客户区(但让标题栏可见)

发布于 2025-01-07 23:38:14 字数 405 浏览 0 评论 0原文

我正在寻找一种开发方法:

Heberger 图片
(来源:hostingpics.net

在表单的标题栏(图片上的矩形 1)上方,表单内容(矩形 2)可见并且可见。当鼠标未悬停时,它会消失,但矩形 1 必须保持可见!

我怎样才能做到这一点?

提前致谢

I'm looking for a way to develop this:

Heberger image
(source: hostingpics.net)

When the mouse is over the form's title bar (rectange 1 on the picture) the form content (the rectangle 2) is visible & when the mouse is not over, it disappears but the rectangle 1 must remain visible!

How could i manage to do that ?

Thanks in advance

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

罪#恶を代价 2025-01-14 23:38:14

有一些与表单非客户区相关的鼠标事件(WM_NCMOUSEMOVEWM_NCMOUSELEAVE...)可用于此目的。但这并不简单,因为它们不包含在 Windows 窗体中。要使用此事件,您应该覆盖表单的WndProc。捕获 WM_NCMOUSEMOVE 事件在某种程度上很简单,但 WM_NCMOSUELEAVE 有点棘手。 Windows 通常不会向窗口发送鼠标离开事件,除非它们使用 TrackMouseEvent 函数显式请求。

下面是完全符合您要求的完整代码:

    protected override void WndProc(ref Message m)
    {
        if (m.Msg == 0xA0) // WM_NCMOUSEMOVE
        {
            TrackNcMouseLeave(this);
            ShowClientArea();
        }
        else if (m.Msg == 0x2A2) // WM_NCMOUSELEAVE
        {
            HideClientAreaIfPointerIsOut();
        }

        base.WndProc(ref m);
    }

    protected override void OnMouseLeave(EventArgs e)
    {
        base.OnMouseLeave(e);
        HideClientAreaIfPointerIsOut();
    }

    private int previouseHeight;

    private void ShowClientArea()
    {
        if (this.ClientSize.Height == 0)
            this.ClientSize = new Size(this.ClientSize.Width, previouseHeight);
    }

    private void HideClientAreaIfPointerIsOut()
    {
        if (this.Bounds.Contains(Cursor.Position))
            return;
        previouseHeight = this.ClientSize.Height;
        this.ClientSize = new Size(this.ClientSize.Width, 0);
    }

    public static void TrackNcMouseLeave(Control control)
    {
        TRACKMOUSEEVENT tme = new TRACKMOUSEEVENT();
        tme.cbSize = (uint)Marshal.SizeOf(tme);
        tme.dwFlags = 2 | 0x10; // TME_LEAVE | TME_NONCLIENT
        tme.hwndTrack = control.Handle;
        TrackMouseEvent(tme);
    }

    [DllImport("user32")]
    public static extern bool TrackMouseEvent([In, Out] TRACKMOUSEEVENT lpEventTrack);

    [StructLayout(LayoutKind.Sequential)]
    public class TRACKMOUSEEVENT
    {
        public uint cbSize;
        public uint dwFlags;
        public IntPtr hwndTrack;
        public uint dwHoverTime;
    }

将此代码部分放入您的表单类中,这样就可以处理所有事情。

通过重写WndProc,我们正在处理所需的鼠标事件。在WM_NCMOUSEMOVE事件中,我们调用一个方法来通知操作系统我们对WM_NCMOUSELEAVE事件感兴趣,并且我们还显示表单的客户区(如果不可见) .
WM_NCMOUSELEAVE 事件中,我们隐藏表单的客户区(如果光标不在表单上)。每次调用WM_NCMOUSELEAVE事件时,TrackMouseEvent请求的所有跟踪事件都会被取消,因此我们必须在中每次调用TrackMouseEvent函数>WM_NCMOUSEMOVE

请注意,此代码中未考虑最大化表单,您应该以某种方式处理它。

There are some mouse events related to the non-client area of the forms (WM_NCMOUSEMOVE, WM_NCMOUSELEAVE, ...) that can be used for this purpose. But this is not simple, because they are not included in Windows Forms. To use this events, you should override WndProc of your form. Catching WM_NCMOUSEMOVE event is somehow simple, but WM_NCMOSUELEAVE is a little tricky. Windows normally does not send mouse leave events to windows, unless they request it explicitly using TrackMouseEvent function.

Here is the complete code that does exactly what you want:

    protected override void WndProc(ref Message m)
    {
        if (m.Msg == 0xA0) // WM_NCMOUSEMOVE
        {
            TrackNcMouseLeave(this);
            ShowClientArea();
        }
        else if (m.Msg == 0x2A2) // WM_NCMOUSELEAVE
        {
            HideClientAreaIfPointerIsOut();
        }

        base.WndProc(ref m);
    }

    protected override void OnMouseLeave(EventArgs e)
    {
        base.OnMouseLeave(e);
        HideClientAreaIfPointerIsOut();
    }

    private int previouseHeight;

    private void ShowClientArea()
    {
        if (this.ClientSize.Height == 0)
            this.ClientSize = new Size(this.ClientSize.Width, previouseHeight);
    }

    private void HideClientAreaIfPointerIsOut()
    {
        if (this.Bounds.Contains(Cursor.Position))
            return;
        previouseHeight = this.ClientSize.Height;
        this.ClientSize = new Size(this.ClientSize.Width, 0);
    }

    public static void TrackNcMouseLeave(Control control)
    {
        TRACKMOUSEEVENT tme = new TRACKMOUSEEVENT();
        tme.cbSize = (uint)Marshal.SizeOf(tme);
        tme.dwFlags = 2 | 0x10; // TME_LEAVE | TME_NONCLIENT
        tme.hwndTrack = control.Handle;
        TrackMouseEvent(tme);
    }

    [DllImport("user32")]
    public static extern bool TrackMouseEvent([In, Out] TRACKMOUSEEVENT lpEventTrack);

    [StructLayout(LayoutKind.Sequential)]
    public class TRACKMOUSEEVENT
    {
        public uint cbSize;
        public uint dwFlags;
        public IntPtr hwndTrack;
        public uint dwHoverTime;
    }

Put this code section in your form class, and that takes care of everything.

By overriding WndProc we are handling required mouse events. In WM_NCMOUSEMOVE event, we call a method to inform the operating system that we are interested in WM_NCMOUSELEAVE event, and also we show the client area of the form (if not visible).
In WM_NCMOUSELEAVE event we hide the client area of the form (if the cursor is not on the form). Every time the WM_NCMOUSELEAVE event is called, all tracking events requested by TrackMouseEvent are canceled, so we must call the TrackMouseEvent function every time in WM_NCMOUSEMOVE.

Be aware that maximizing the form is not considered in this code and you should handle it somehow.

爺獨霸怡葒院 2025-01-14 23:38:14

我建议您制作一个无边框表单,并使用停靠在顶部的自定义控件作为标题栏。然后它就变得像在 MouseEnter 和 MouseLeave 事件上更改表单的高度一样简单!

希望有帮助!

I suggest that you make a borderless form and use a custom control docked to the top as the title bar. Then it becomes as simple as changing the height of the form on MouseEnter and MouseLeave events!

Hope that helps!

池予 2025-01-14 23:38:14

知道您的 Form BorderStyle 设置为 None,您可以根据鼠标的位置和矩形的大小来开发一些内容,因此您必须使用 MouseEnterMouseLeave 事件,如 Digvijay 所说>。

这是我的示例代码:

    private void Rectangle1_MouseEnter(object sender, EventArgs e)
    {
        myForm.Height = Rectangle1.Height + Rectangle2.Height;
    }

    private void Rectangle1_MouseLeave(object sender, EventArgs e)
    {
        if (!myForm.Bounds.Contains(MousePosition))
        {
            myForm.Height = Rectangle1.Height;
        }
    }

Knowing that your Form BorderStyle is set on None, you can develop something based on the position of the mouse and the size of your rectangles, so you must use the MouseEnter and MouseLeave event as said Digvijay.

Here is my sample code:

    private void Rectangle1_MouseEnter(object sender, EventArgs e)
    {
        myForm.Height = Rectangle1.Height + Rectangle2.Height;
    }

    private void Rectangle1_MouseLeave(object sender, EventArgs e)
    {
        if (!myForm.Bounds.Contains(MousePosition))
        {
            myForm.Height = Rectangle1.Height;
        }
    }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文