【问题标题】:Restrict resizable panel (ratio & min/max size)限制可调整大小的面板(比率和最小/最大尺寸)
【发布时间】:2017-09-30 02:45:55
【问题描述】:

我目前正在尝试将可调整大小的面板添加到我的 C# winforms 项目中。

目前我正在使用此代码来获得我想要的:

using System;
using System.Drawing;
using System.Windows.Forms;

class ResizablePanel : Panel
{
    private const int grab = 16;

    public ResizablePanel()
    {
        this.ResizeRedraw = true;
    }

    protected override void OnPaint(PaintEventArgs e)
    {
        base.OnPaint(e);
        var rc = new Rectangle(this.ClientSize.Width - grab, this.ClientSize.Height - grab, grab, grab);
        ControlPaint.DrawSizeGrip(e.Graphics, this.BackColor, rc);
    }

    protected override void WndProc(ref Message m)
    {
        base.WndProc(ref m);

        if (m.Msg == 0x84)
        {
            var pos = this.PointToClient(new Point(m.LParam.ToInt32() & 0xffff, m.LParam.ToInt32() >> 16));

            if (pos.X >= this.ClientSize.Width - grab && pos.Y >= this.ClientSize.Height - grab)
                m.Result = new IntPtr(17);
        }
    }
}

它工作正常,但现在我想限制一些事情。

  1. 我不希望面板小于 420x236。 我尝试设置 MinimumSize,但当我尝试调整大小时它忽略了这一点。

  2. 我想保持 16:9 的纵横比。

我将如何使用上面的代码得到它?有什么办法吗?

【问题讨论】:

  • 你试过SetBoundsCore()吗?它是一种虚拟方法,您可以在像您这样的情况下使用它。

标签: c# winforms panel aspect-ratio resizable


【解决方案1】:

处理来自this answer的WM_SIZING消息。

if (m.Msg == 0x84)
{
    var pos = this.PointToClient(new Point(m.LParam.ToInt32() & 0xffff, m.LParam.ToInt32() >> 16));

    if (pos.X >= this.ClientSize.Width - grab && pos.Y >= this.ClientSize.Height - grab)
    m.Result = new IntPtr(17);
}
else if (m.Msg == 0x216 || m.Msg == 0x214)
{ 
    // WM_MOVING || WM_SIZING
    // Keep the aspect and minimum size
    RECT rc = (RECT)Marshal.PtrToStructure(m.LParam, typeof(RECT));
    int w = rc.Right - rc.Left;
    int h = rc.Bottom - rc.Top;
    w = w > 420 ? w : 420;
    rc.Bottom = rc.Top + (int)(w * 9.0 / 16);
    rc.Right = rc.Left + w;
    Marshal.StructureToPtr(rc, m.LParam, false);
    m.Result = (IntPtr)1;
    return;
}

RECT 结构体定义为

[StructLayout(LayoutKind.Sequential)]
public struct RECT {
    public int Left;
    public int Top;
    public int Right;
    public int Bottom;
}

我也尝试过覆盖OnResize 事件,这要简单得多,但是,面板在调整大小时会闪烁。

protected override void OnResize(EventArgs eventargs)
{
    base.OnResize(eventargs);
    if (this.Width < 420)
        this.Size = new Size(420, 236);
    else
        this.Size = new Size(this.Width, (int)(this.Width * 9.0 / 16));
}

这两种方法实际上是一样的,处理消息队列是更底层的“Win32-like”,而覆盖 OnResize 是“Windows 窗体的方式”。

【讨论】:

  • 所以我尝试了 OnResize 版本,它工作正常。我通过使用 DoubleBuffered 并覆盖 CreateParams 修复了闪烁。即使 OnResize 正在工作,我仍然想测试您的想法的第一个版本,但我不明白如何/在哪里使用它。我对所有这些东西都很陌生,还在学习,你能给我一个关于在哪里以及如何使用它的小“教程”吗?
  • 哦,我看到我还需要根据表单的大小来限制最大高度/宽度,因为如果你把它拉伸得太大,你就不能抓住角落让它变小了. :D
  • 只需将代码复制到您的 WndProc 方法中,我只是在您的 if 之后添加一个 else if。
  • @kennyzy 该死的,看来我需要休息一下,就这样,谢谢!^^ RECT 呢?它不是一个矩形,它是什么?
  • @Backslash 是的,它相当于 Win32 中的 Rectangle
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多