在c#中调整大小时保留表单宽高比

时间:2010-08-02 20:18:33

标签: c# winforms aspect-ratio

如何使表单具有固定的宽高比,并在调整大小时保留?

我知道可以通过覆盖OnSizeChanged并手动修改[new]高度/宽度来完成,但这会导致闪烁,因为它会在调用事件之前调整一次(大小与宽高比不匹配) )然后再次调整大小(达到正确的宽高比)。还有更好的方法吗?

2 个答案:

答案 0 :(得分:11)

一些代码可以帮助您入门。关键是响应WM_SIZING消息,它允许您更改窗口矩形。这个样本很粗糙,你真的要注意用户拖动的角落或边缘,可以从m.WParam获得。用户界面永远不会很好,当用户拖动角落时,你无法做任何合理的事情。使您的表单布局足够灵活,以便您不关心方面比例是真正的解决方案。当内容不适合时,显示滚动条可让用户自动执行正确的操作。

using System.Runtime.InteropServices;
// etc..

public partial class Form1 : Form {
    public Form1() {
        InitializeComponent();
    }
    protected override void WndProc(ref Message m) {
        if (m.Msg == 0x216 || m.Msg == 0x214) { // WM_MOVING || WM_SIZING
            // Keep the window square
            RECT rc = (RECT)Marshal.PtrToStructure(m.LParam, typeof(RECT));
            int w = rc.Right - rc.Left;
            int h = rc.Bottom - rc.Top;
            int z = w > h ? w : h;
            rc.Bottom = rc.Top + z;
            rc.Right = rc.Left + z;
            Marshal.StructureToPtr(rc, m.LParam, false);
            m.Result = (IntPtr)1;
            return;
        }
        base.WndProc(ref m);
    }
    [StructLayout(LayoutKind.Sequential)]
    public struct RECT {
        public int Left;
        public int Top;
        public int Right;
        public int Bottom;
    }
}

答案 1 :(得分:0)

扩展接受的答案:

protected override void WndProc(ref Message m)
    {
        /*
        internal const int WMSZ_LEFT = 1;
        internal const int WMSZ_RIGHT = 2;
        internal const int WMSZ_TOP = 3;
        internal const int WMSZ_TOPLEFT = 4;
        internal const int WMSZ_TOPRIGHT = 5;
        internal const int WMSZ_BOTTOM = 6;
        internal const int WMSZ_BOTTOMLEFT = 7;
        internal const int WMSZ_BOTTOMRIGHT = 8;
        */

        if (m.Msg == 0x214)
        { // WM_MOVING || WM_SIZING
          // Keep the window square
            RECT rc = (RECT)Marshal.PtrToStructure(m.LParam, typeof(RECT));
            int w = rc.Right - rc.Left; // get width
            int h = rc.Bottom - rc.Top; // get height
            int z = w > h ? w : h; // z is greatest of the two (w/h)
            switch ((int)m.WParam)
            {
                case 1: //left
                    rc.Bottom = rc.Top + w;//define width
                    rc.Top = rc.Top + (h - (rc.Bottom - rc.Top)) / 2;//define width
                    break;
                case 2: //right
                    rc.Bottom = rc.Top + w;//define width
                    rc.Top = rc.Top + (h - (rc.Bottom - rc.Top)) / 2;//define width
                    break;
                case 3: //top
                    rc.Right = rc.Left + h;//define width
                    rc.Left = rc.Left + (w - (rc.Right - rc.Left)) / 2;//define width
                    break;
                case 4:
                    rc.Top = rc.Bottom - z;//define height
                    rc.Left = rc.Right - z;//define width
                    break;
                case 5:
                    rc.Top = rc.Bottom - z;//define height
                    rc.Right = rc.Left + z;//define width
                    break;
                case 6:
                    rc.Right = rc.Left + h;//define width
                    rc.Left = rc.Left + (w-(rc.Right - rc.Left))/2;//define width
                    break;
                case 7:
                    rc.Bottom = rc.Top + z;//define height
                    rc.Left = rc.Right - z;//define width
                    break;
                case 8:
                    rc.Bottom = rc.Top + z;//define height
                    rc.Right = rc.Left + z;//define width
                    break;
                default:
                    break;
            }
            Marshal.StructureToPtr(rc, m.LParam, false);
            m.Result = (IntPtr)1;
            return;
        }
        base.WndProc(ref m);
    }
    [StructLayout(LayoutKind.Sequential)]
    public struct RECT
    {
        public int Left;
        public int Top;
        public int Right;
        public int Bottom;
    }