如何使用窗体边框上的控件来修复无边框窗体调整大小? [英] How to fix borderless form resize with controls on borders of the form?

查看:87
本文介绍了如何使用窗体边框上的控件来修复无边框窗体调整大小?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个无边界的winForm,需要调整其大小,并且设法做到了这一点:

I have a borderless winForm which I needed to resize, and I managed to do it this way:

protected override void WndProc(ref Message m)
    {
        const int wmNcHitTest = 0x84;
        const int htLeft = 10;
        const int htRight = 11;
        const int htTop = 12;
        const int htTopLeft = 13;
        const int htTopRight = 14;
        const int htBottom = 15;
        const int htBottomLeft = 16;
        const int htBottomRight = 17;

        if (m.Msg == wmNcHitTest)
        {
            Console.Write(true + "\n");
            int x = (int)(m.LParam.ToInt64() & 0xFFFF);
            int y = (int)((m.LParam.ToInt64() & 0xFFFF0000) >> 16);
            Point pt = PointToClient(new Point(x, y));
            Size clientSize = ClientSize;
            ///allow resize on the lower right corner
            if (pt.X >= clientSize.Width - 16 && pt.Y >= clientSize.Height - 16 && clientSize.Height >= 16)
            {
                m.Result = (IntPtr)(IsMirrored ? htBottomLeft : htBottomRight);
                return;
            }
            ///allow resize on the lower left corner
            if (pt.X <= 16 && pt.Y >= clientSize.Height - 16 && clientSize.Height >= 16)
            {
                m.Result = (IntPtr)(IsMirrored ? htBottomRight : htBottomLeft);
                return;
            }
            ///allow resize on the upper right corner
            if (pt.X <= 16 && pt.Y <= 16 && clientSize.Height >= 16)
            {
                m.Result = (IntPtr)(IsMirrored ? htTopRight : htTopLeft);
                return;
            }
            ///allow resize on the upper left corner
            if (pt.X >= clientSize.Width - 16 && pt.Y <= 16 && clientSize.Height >= 16)
            {
                m.Result = (IntPtr)(IsMirrored ? htTopLeft : htTopRight);
                return;
            }
            ///allow resize on the top border
            if (pt.Y <= 16 && clientSize.Height >= 16)
            {
                m.Result = (IntPtr)(htTop);
                return;
            }
            ///allow resize on the bottom border
            if (pt.Y >= clientSize.Height - 16 && clientSize.Height >= 16)
            {
                m.Result = (IntPtr)(htBottom);
                return;
            }
            ///allow resize on the left border
            if (pt.X <= 16 && clientSize.Height >= 16)
            {
                m.Result = (IntPtr)(htLeft);
                return;
            }
            ///allow resize on the right border
            if (pt.X >= clientSize.Width - 16 && clientSize.Height >= 16)
            {
                m.Result = (IntPtr)(htRight);
                return;
            }
        }
        else
        {
            Console.Write(false + "\n");
        }
        base.WndProc(ref m);
    }

问题是我的表单左右边框都有控件,因此上面代码中使用的调整大小覆盖不适用于存在任何类型控件的那些区域。

The problem is that there are controls on the left and right borders of my form, so the resize override used on the code above doesn't work on those areas in which there are controls of any kind.

这里是一个示例:

在上图中,您可以看到标记区域内的标签在表单的左边框上

On the image above you can see that the label inside the marked area is on the left border of my form and it won't let me resize it.

有没有办法解决这个问题?

Is there a way to solve this issue?

推荐答案

这里的问题是获取鼠标通知的是Label控件,而不是无边界表单。到目前为止,解决此问题的最佳方法是使标签对鼠标透明。您已经知道该怎么做,WM_NCHITTEST还允许返回HTTRANSPARENT。 Windows会继续寻找该通知的下一个候选对象,它将是标签的父对象。

The problem here is that it is the Label control that gets the mouse notifications, not your borderless form. By far the best way to solve this problem is making the label transparent to the mouse. You already know how to do that, WM_NCHITTEST also permits returning HTTRANSPARENT. Windows keeps looking for the next candidate for the notification, it will be the label's Parent.

由于通常您的鼠标事件根本没有任何用处,因此标签的制作特别容易:

Especially easy to do for a label since you don't normally have any use for its mouse events at all:

using System;
using System.Windows.Forms;

public class LabelEx : Label {
    protected override void WndProc(ref Message m) {
        const int wmNcHitTest = 0x84;
        const int htTransparent = -1;
        if (!DesignMode && m.Msg == wmNcHitTest) m.Result = new IntPtr(htTransparent);
        else base.WndProc(ref m);
    }
}

适用于任何Control类,您想要如果是按钮,则更具选择性。可能只是您所需要的,但是如果您在边缘附近有许多不同类型的控件,仍然会很尴尬。您可以使用的另一种技术在本机Windows编程中称为子类。在Winforms中普遍使用,以为本机Windows控件创建包装.NET类。它在这里也很好用,您可以窥视任何控件的消息并以这种方式拦截WM_NCHITTEST:

Works for any Control class, you'd want to be more selective if it were a button. Might be all you need, still pretty awkward however if you have a lot of different kind of controls close to the edge. Another technique you can use is called "sub-classing" in native Windows programming. Universally used in Winforms to create wrapper .NET classes for native Windows controls. It works well here too, you can have a peek at the messages of any control and intercept WM_NCHITTEST that way:

    const int edge = 16;

    class MouseFilter : NativeWindow {
        private Form form;
        public MouseFilter(Form form, Control child) {
            this.form = form;
            this.AssignHandle(child.Handle);
        }
        protected override void WndProc(ref Message m) {
            const int wmNcHitTest = 0x84;
            const int htTransparent = -1;

            if (m.Msg == wmNcHitTest) {
                var pos = new Point(m.LParam.ToInt32());
                if (pos.X < this.form.Left + edge ||
                    pos.Y < this.form.Top + edge||
                    pos.X > this.form.Right - edge ||
                    pos.Y > this.form.Bottom - edge) {
                    m.Result = new IntPtr(htTransparent);
                    return;
                }
            }
            base.WndProc(ref m);
        }
    }

只需为每个要获取的控件创建一个MouseFilter实例靠近窗口边缘:

And just create a MouseFilter instance for every control that gets close to the window edge:

    protected override void OnLoad(EventArgs e) {
        base.OnLoad(e);
        subClassChildren(this.Controls);
    }

    private void subClassChildren(Control.ControlCollection ctls) {
        foreach (Control ctl in ctls) {
            var rc = this.RectangleToClient(this.RectangleToScreen(ctl.DisplayRectangle));
            if (rc.Left < edge || rc.Right > this.ClientSize.Width - edge ||
                rc.Top < edge || rc.Bottom > this.ClientSize.Height - edge) {
                new MouseFilter(this, ctl);
            }
            subClassChildren(ctl.Controls);
        }
    }

这篇关于如何使用窗体边框上的控件来修复无边框窗体调整大小?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆