C# 调整右下角无边框窗口的大小

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1535826/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 18:31:37  来源:igfitidea点击:

Resize borderless window on bottom right corner

c#winforms

提问by Chris U

I'd like the user to resize a borderless window on bottom right corner like I can resize the autocomplete window of the combobox control.

我希望用户调整右下角的无边框窗口的大小,就像我可以调整组合框控件的自动完成窗口的大小一样。

I cannot find the properties to configure a form that way.

我找不到以这种方式配置表单的属性。

Maybe someone could help me on the problem.

也许有人可以帮助我解决这个问题。

An image could be found here:

可以在此处找到图像:

enter image description here

在此处输入图片说明

采纳答案by Franci Penov

The proper way to achieve this would be to add a message proc handler (by overriding Form.WndProcfor example) to your form and handle the WM_NCHITTESTmessage. (You can find the C# definition of that message on PInvoke.net) In particular, when you receive the message, calculate if the hit test is for a point in the region you've designated for resize and if it is, return HTBOTTOMRIGHT. The default window proc will do the rest for you, as it will assume that the user has clicked on the bottom right corner of the window border, even though your window has no border.

实现此目的的正确方法是向Form.WndProc表单添加消息处理程序(例如通过覆盖)并处理WM_NCHITTEST消息。(您可以在PInvoke.net上找到该消息的 C# 定义)特别是,当您收到该消息时,计算命中测试是否针对您指定用于调整大小的区域中的某个点,如果是,则返回 HTBOTTOMRIGHT。默认窗口 proc 将为您完成剩下的工作,因为它会假设用户单击了窗口边框的右下角,即使您的窗口没有边框。

This aproach requires a teensy bit of Win32 interop, but it'll make your resize look exactly like any other window resize.

这种方法需要一点 Win32 互操作,但它会使您的调整大小看起来与任何其他窗口调整大小完全一样。

The easy way would be to do as @benPearce said and put a panel in the corner and adjust the form size using Width/Height. It's going to work, but the resize is not going to be smooth, especially on Vista and Win7 Basic, where full redraw is disabled on standard move and resize, while is going to attempt redraw on every step.

简单的方法是按照@benPearce 所说的做,在角落里放一个面板,然后使用宽度/高度调整表单大小。它将起作用,但调整大小不会顺利,尤其是在 Vista 和 Win7 Basic 上,在标准移动和调整大小时禁用完全重绘,同时将在每一步尝试重绘。

Update: In both approaches you will have to figure out also how to paint the gripper. You can put a bitmap of the standard gripper, for example. Though, given that your form has no title and border so you are not necessarily stuck with the standard Windows visuals, you might opt in for something snazzier.

更新:在这两种方法中,您还必须弄清楚如何绘制夹具。例如,您可以放置​​标准夹具的位图。不过,鉴于您的表单没有标题和边框,因此您不一定会使用标准的 Windows 视觉效果,您可能会选择一些更时髦的东西。

Update 2: If you have a control that covers the whole window, it will eat the form mouse messages. You have to somehow clip the place you want to use for resizing out of that control. You have several options to deal with this:

更新 2:如果您有一个覆盖整个窗口的控件,它会吃掉表单鼠标消息。您必须以某种方式剪辑要用于调整大小的位置,使其脱离该控制。您有多种选择来处理这个问题:

  1. Resize the control to make some space for the resizing grip.
  2. Tweak the control region (throug the Region property) to exclude the resizing grip.
  3. Cover the resizing grip a panel, listen to its MouseEnter message and set the form Capture property to true, which will cause all further mouse messages to go to it. Note: you will have to release the capture once the mouse leaves that region after the resize is finished.
  1. 调整控件的大小,为调整大小的手柄留出一些空间。
  2. 调整控制区域(通过 Region 属性)以排除调整大小的夹点。
  3. 覆盖调整大小控制面板,收听它的 MouseEnter 消息并将表单 Capture 属性设置为 true,这将导致所有进一步的鼠标消息转到它。注意:调整大小完成后,一旦鼠标离开该区域,您就必须释放捕获。

I would recommend to go for option 1 as the simplest. Option 3 is the most complex and would require intimate details on how mouse input works in Windows, so I wouldn't recommend it. Option 2 is a good alternative to option 1, but you'll have to give it a try to see how the ListView control would react to its region being tweaked.

我建议选择最简单的选项 1。选项 3 是最复杂的,需要详细了解鼠标输入在 Windows 中的工作方式,因此我不推荐它。选项 2 是选项 1 的一个很好的替代方法,但您必须尝试一下,看看 ListView 控件如何对其被调整的区域做出反应。

回答by benPearce

Put a panel or some other control in the corner, using the MouseDown and MouseMove events of the panel, adjust the forms size appropriately.

将面板或其他控件放在角落,使用面板的 MouseDown 和 MouseMove 事件,适当调整表单大小。

In MouseDown, i would record the coordinates, then in the MouseMove you can calculate the difference from the original position to adjust the forms size.

在 MouseDown 中,我会记录坐标,然后在 MouseMove 中您可以计算与原始位置的差异以调整表单大小。

回答by Julien Lebosquain

Here's the code corresponding to Franci's explanations, I was writing it but he answered meanwhile so vote up his explanation which is good if this code suits your needs.

这是与 Franci 的解释相对应的代码,我正在编写它,但他同时回答了所以投票他的解释,如果此代码适合您的需要,这很好。

protected override void WndProc(ref Message m) {
    const int wmNcHitTest = 0x84;
    const int htBottomLeft = 16;
    const int htBottomRight = 17;
    if (m.Msg == wmNcHitTest) {
        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;
        if (pt.X >= clientSize.Width - 16 && pt.Y >= clientSize.Height - 16 && clientSize.Height >= 16) {
            m.Result = (IntPtr) (IsMirrored ? htBottomLeft : htBottomRight);
            return;
        }
    }
    base.WndProc(ref m);
}

Edit: to write the gripper, you can initialize a new VisualStyleRenderer(VisualStyleElement.Status.Gripper.Normal)and use its PaintBackground()method.

编辑:要编写夹具,您可以初始化 anew VisualStyleRenderer(VisualStyleElement.Status.Gripper.Normal)并使用其PaintBackground()方法。

回答by dizzy.stackoverflow

Thanks so much for posting this great sample and explanation. I've added some additions below that others might be interested in. Some of the code here came from other stackoverflow postings, but to be able to see it in one code block might be helpful to others. I wanted to be able to resize the form on ALL borders, not just the lower right corner. I also wanted to be able to drag the form around. Lastly, I wanted a drop-shadow.

非常感谢您发布这个很棒的示例和解释。我在下面添加了一些其他人可能感兴趣的补充。这里的一些代码来自其他 stackoverflow 帖子,但能够在一个代码块中看到它可能对其他人有帮助。 我希望能够在所有边框上调整表单的大小,而不仅仅是右下角。我还希望能够拖动表单。最后,我想要一个阴影。

//***********************************************************
//This gives us the ability to resize the borderless from any borders instead of just the lower right corner
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)
    {
        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;
        }
    }
    base.WndProc(ref m);
}
//***********************************************************
//***********************************************************
//This gives us the ability to drag the borderless form to a new location
public const int WM_NCLBUTTONDOWN = 0xA1;
public const int HT_CAPTION = 0x2;

[DllImportAttribute("user32.dll")]
public static extern int SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam);
[DllImportAttribute("user32.dll")]
public static extern bool ReleaseCapture();

private void YOURCONTROL_MouseDown(object sender, MouseEventArgs e)
{
    //ctrl-leftclick anywhere on the control to drag the form to a new location 
    if (e.Button == MouseButtons.Left && Control.ModifierKeys == Keys.Control)
    {       
        ReleaseCapture();
        SendMessage(Handle, WM_NCLBUTTONDOWN, HT_CAPTION, 0);
    }  
}
//***********************************************************
//***********************************************************
//This gives us the drop shadow behind the borderless form
private const int CS_DROPSHADOW = 0x20000;
protected override CreateParams CreateParams
{
    get
    {
        CreateParams cp = base.CreateParams;
        cp.ClassStyle |= CS_DROPSHADOW;
        return cp;
    }
}
//***********************************************************