无边框形式 C# 中的自定义调整大小句柄 [英] Custom Resize Handle in Border-less Form C#

查看:24
本文介绍了无边框形式 C# 中的自定义调整大小句柄的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试制作从工具栏弹出的无边框表单.我希望用户能够抓住右下角(调整大小手柄")并能够调整表单大小,但不能以任何其他方式调整表单大小或重新定位.

I'm attempting to make border-less forms that pop out of a tool bar. I want the user to be able to grab at the bottom-right corner (a "resize handle") and be able to resize the form, but not be able to resize or reposition the form in any other way.

我听说我可以拦截发送到表单的 WM_NCHITTEST 消息并将其结果设置为 HTBOTTOMRIGHT,这将使操作系统处理重新调整大小形式,就好像它有一个相当大的框架.我的想法是检测鼠标指针是否进入了我在角落定义的框,如果进入,则返回 HTBOTTOMRIGHT 结果.

I've heard that I can intercept the WM_NCHITTEST message sent to the form and set its result to HTBOTTOMRIGHT which will let the operating system handle the re-sizing of the form, just as if it had a sizable frame. The idea I had was to detect if the mouse pointer had entered a box I defined in the corner and if it did then return the HTBOTTOMRIGHT result.

这并不像我预期的那样有效.我能够拦截消息,但似乎只有当用户将鼠标光标放在表单的 1px 粗边框上时才会发送消息.这意味着如果您非常精确地将光标定位在右下边缘,它会按照我想要的方式工作.

This doesn't quite work as I expected it to. I'm able to intercept the message, but it seems the message is only sent when the user positions the mouse cursor on the 1px thick border of the form. That means it works how I want to, if you very precisely position your cursor on the bottom-right edges.

这是我的 WndProc 覆盖:

protected override void WndProc(ref Message m)
{
    const UInt32 WM_NCHITTEST = 0x0084;
    const UInt32 HTBOTTOMRIGHT = 17;
    const int RESIZE_HANDLE_SIZE = 40;
    bool handled = false;
    if (m.Msg == WM_NCHITTEST)
    {
        Size formSize = this.Size;
        Point screenPoint = new Point(m.LParam.ToInt32());
        Point clientPoint = this.PointToClient(screenPoint);
        Rectangle hitBox = new Rectangle(formSize.Width - RESIZE_HANDLE_SIZE, formSize.Height - RESIZE_HANDLE_SIZE, RESIZE_HANDLE_SIZE, RESIZE_HANDLE_SIZE);
        if (hitBox.Contains(clientPoint))
        {
            m.Result = (IntPtr)HTBOTTOMRIGHT;
            handled = true;
        }
    }

    if (!handled)
        base.WndProc(ref m);
}

我做错了什么还是有更好的方法来做我想做的事?

Am I doing something wrong or is there a better way to do what I'm trying to do?

非常感谢.

推荐答案

我一直在寻找类似的东西,Anton 的代码是一个很好的基础.这就是我最终从各个方面调整大小的工作.我不确定 Dictionary 是存储命中框的最佳方式,但我想这并不重要.

I was looking for something similar and Anton's code was a great base. This is what I ended up to have resize work from all sides. I'm unsure a Dictionary was optimal way to store the hitboxes, but I guess it doesn't matter all that much.

并且由于我的表单中填充了使用 Fill as Dock 参数的控件,我只需要在 Form 中添加一个 5px 的填充以使其正常工作.

And since my form is filled with controls using Fill as Dock parameters, I just had to add a 5px padding to the Form for it to work nicely.

protected override void WndProc(ref Message m)
{
    const UInt32 WM_NCHITTEST = 0x0084;
    const UInt32 WM_MOUSEMOVE = 0x0200;

    const UInt32 HTLEFT = 10;
    const UInt32 HTRIGHT = 11;
    const UInt32 HTBOTTOMRIGHT = 17;
    const UInt32 HTBOTTOM = 15;
    const UInt32 HTBOTTOMLEFT = 16;
    const UInt32 HTTOP = 12;
    const UInt32 HTTOPLEFT = 13;
    const UInt32 HTTOPRIGHT = 14;

    const int RESIZE_HANDLE_SIZE = 10;
    bool handled = false;
    if (m.Msg == WM_NCHITTEST || m.Msg == WM_MOUSEMOVE)
    {
        Size formSize = this.Size;
        Point screenPoint = new Point(m.LParam.ToInt32());
        Point clientPoint = this.PointToClient(screenPoint);

        Dictionary<UInt32, Rectangle> boxes = new Dictionary<UInt32, Rectangle>() {
            {HTBOTTOMLEFT, new Rectangle(0, formSize.Height - RESIZE_HANDLE_SIZE, RESIZE_HANDLE_SIZE, RESIZE_HANDLE_SIZE)},
            {HTBOTTOM, new Rectangle(RESIZE_HANDLE_SIZE, formSize.Height - RESIZE_HANDLE_SIZE, formSize.Width - 2*RESIZE_HANDLE_SIZE, RESIZE_HANDLE_SIZE)},
            {HTBOTTOMRIGHT, new Rectangle(formSize.Width - RESIZE_HANDLE_SIZE, formSize.Height - RESIZE_HANDLE_SIZE, RESIZE_HANDLE_SIZE, RESIZE_HANDLE_SIZE)},
            {HTRIGHT, new Rectangle(formSize.Width - RESIZE_HANDLE_SIZE, RESIZE_HANDLE_SIZE, RESIZE_HANDLE_SIZE, formSize.Height - 2*RESIZE_HANDLE_SIZE)},
            {HTTOPRIGHT, new Rectangle(formSize.Width - RESIZE_HANDLE_SIZE, 0, RESIZE_HANDLE_SIZE, RESIZE_HANDLE_SIZE) },
            {HTTOP, new Rectangle(RESIZE_HANDLE_SIZE, 0, formSize.Width - 2*RESIZE_HANDLE_SIZE, RESIZE_HANDLE_SIZE) },
            {HTTOPLEFT, new Rectangle(0, 0, RESIZE_HANDLE_SIZE, RESIZE_HANDLE_SIZE) },
            {HTLEFT, new Rectangle(0, RESIZE_HANDLE_SIZE, RESIZE_HANDLE_SIZE, formSize.Height - 2*RESIZE_HANDLE_SIZE) }
        };

        foreach (KeyValuePair<UInt32, Rectangle> hitBox in boxes)
        {
            if (hitBox.Value.Contains(clientPoint))
            {
                m.Result = (IntPtr) hitBox.Key;
                handled = true;
                break;
            }
        }
    }

    if (!handled)
        base.WndProc(ref m);
}

这篇关于无边框形式 C# 中的自定义调整大小句柄的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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