限制可调整大小的面板(比例和 min/max 大小)
Restrict resizable panel (ratio & min/max size)
我目前正在尝试向我的 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);
}
}
}
它工作正常,但现在我想限制一些事情。
我不希望面板小于 420x236。
我尝试设置 MinimumSize,但当我尝试调整大小时它忽略了它。
我想保持 16:9 的纵横比。
我如何用上面的代码得到它?有什么办法吗?
处理 WM_SIZING 消息,采用自 this answer。
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 Forms' way"。
我目前正在尝试向我的 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);
}
}
}
它工作正常,但现在我想限制一些事情。
我不希望面板小于 420x236。 我尝试设置 MinimumSize,但当我尝试调整大小时它忽略了它。
我想保持 16:9 的纵横比。
我如何用上面的代码得到它?有什么办法吗?
处理 WM_SIZING 消息,采用自 this answer。
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 Forms' way"。