如何在没有边框的情况下移动和调整窗体大小?

40

有人知道如何在无边框的窗体中调整大小吗?我不想要Windows默认的边框,所以将“FormBorderStyle”属性更改为“None”。这样移除了边框,但现在不能调整大小。我已经找到如何移动窗体的方法,只需要知道如何调整大小。

7个回答

74

以下是一些示例代码,可以允许移动和调整窗体大小:

  public partial class Form1 : Form {
    public Form1() {
      InitializeComponent();
      this.FormBorderStyle = FormBorderStyle.None;
      this.DoubleBuffered = true;
      this.SetStyle(ControlStyles.ResizeRedraw, true);
    }
    private const int cGrip = 16;      // Grip size
    private const int cCaption = 32;   // Caption bar height;

    protected override void OnPaint(PaintEventArgs e) {
      Rectangle rc = new Rectangle(this.ClientSize.Width - cGrip, this.ClientSize.Height - cGrip, cGrip, cGrip);
      ControlPaint.DrawSizeGrip(e.Graphics, this.BackColor, rc);
      rc = new Rectangle(0, 0, this.ClientSize.Width, cCaption);
      e.Graphics.FillRectangle(Brushes.DarkBlue, rc);
    }

    protected override void WndProc(ref Message m) {
      if (m.Msg == 0x84) {  // Trap WM_NCHITTEST
        Point pos = new Point(m.LParam.ToInt32());
        pos = this.PointToClient(pos);
        if (pos.Y < cCaption) {
          m.Result = (IntPtr)2;  // HTCAPTION
          return;
        }
        if (pos.X >= this.ClientSize.Width - cGrip && pos.Y >= this.ClientSize.Height - cGrip) {
          m.Result = (IntPtr)17; // HTBOTTOMRIGHT
          return;
        }
      }
      base.WndProc(ref m);
    }
  }

这样我在顶部得到一个蓝色丑陋的条形。 - C4d
1
如果你不想要顶部的栏,就不要覆盖OnPaint()方法。其余代码都很稳定。非常感谢,伙计 :) - kurt
2
要删除顶部边框并仅保留大小调整手柄,请简单地删除OnPaint方法的最后两行:rc = new Rectangle(0, 0, this.ClientSize.Width, cCaption); e.Graphics.FillRectangle(Brushes.DarkBlue, rc); - ryancdotnet
我需要包含特殊的内容吗?因为我无法使其工作。看起来WndProc被调用,但m.Msg从未等于0x84。.NET Framework 4.8 - LongToeBoy
1
没事了。我的窗体中有一个 dock: fill 的面板,因此它完全覆盖了客户区域,鼠标始终悬停在控件上,从未到达客户区域,因此 WM_NCHITTEST 从未触发... 只需取消停靠即可解决问题。 - LongToeBoy
这个程序可以运行,但是在向左或向上拉动时,窗体内部的控件会出现很多“抖动”。同样的问题也出现在窗体的相反边缘。看起来WM_NCHITTEST调用在窗体移动之后才发生(或其他什么情况),代码会将其重新设置到原来的位置。虽然不是什么大问题,但看起来还是很难受的。DoubleBuffered和ResizeRedraw标志不能解决它。 - user1908746

33

这是一个完整的自定义表单示例,包括所有8个调整大小点:

public partial class Form1 : Form {
public Form1() {
  InitializeComponent();
  this.FormBorderStyle = FormBorderStyle.None; // no borders
  this.DoubleBuffered = true;
  this.SetStyle(ControlStyles.ResizeRedraw, true); // this is to avoid visual artifacts
}

protected override void OnPaint(PaintEventArgs e) // you can safely omit this method if you want
{
    e.Graphics.FillRectangle(Brushes.Green, Top);
    e.Graphics.FillRectangle(Brushes.Green, Left);
    e.Graphics.FillRectangle(Brushes.Green, Right);
    e.Graphics.FillRectangle(Brushes.Green, Bottom);
}

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

const int _ = 10; // you can rename this variable if you like

Rectangle Top { get { return new Rectangle(0, 0, this.ClientSize.Width, _); } }
Rectangle Left { get { return new Rectangle(0, 0, _, this.ClientSize.Height); } }
Rectangle Bottom { get { return new Rectangle(0, this.ClientSize.Height - _, this.ClientSize.Width, _); } }
Rectangle Right { get { return new Rectangle(this.ClientSize.Width - _, 0, _, this.ClientSize.Height); } }

Rectangle TopLeft { get { return new Rectangle(0, 0, _, _); } }
Rectangle TopRight { get { return new Rectangle(this.ClientSize.Width - _, 0, _, _); } }
Rectangle BottomLeft { get { return new Rectangle(0, this.ClientSize.Height - _, _, _); } }
Rectangle BottomRight { get { return new Rectangle(this.ClientSize.Width - _, this.ClientSize.Height - _, _, _); } }


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

    if (message.Msg == 0x84) // WM_NCHITTEST
    {
        var cursor = this.PointToClient(Cursor.Position);

        if (TopLeft.Contains(cursor)) message.Result = (IntPtr)HTTOPLEFT;
   else if (TopRight.Contains(cursor)) message.Result = (IntPtr)HTTOPRIGHT;
   else if (BottomLeft.Contains(cursor)) message.Result = (IntPtr)HTBOTTOMLEFT;
   else if (BottomRight.Contains(cursor)) message.Result = (IntPtr)HTBOTTOMRIGHT;

   else if (Top.Contains(cursor)) message.Result = (IntPtr)HTTOP;
   else if (Left.Contains(cursor)) message.Result = (IntPtr)HTLEFT;
   else if (Right.Contains(cursor)) message.Result = (IntPtr)HTRIGHT;
   else if (Bottom.Contains(cursor)) message.Result = (IntPtr)HTBOTTOM;
    }
}}

2
有一个小错误。边缘和角落重叠了,例如返回顶部的代码应该是:new Rectangle(0, 0, this.ClientSize.Width, _);必须更改为:new Rectangle(_, 0, this.ClientSize.Width - _, _);以便留出小正方形给角落...其他边缘也需要相应的偏移量。 - LongToeBoy
“error”没有关系,因为在检查边缘之前会先检查角落。 - Penguin

11

“Sizer” 是右下角浅蓝色面板。

Sizer 截图

    int Mx;
    int My;
    int Sw;
    int Sh;

    bool mov;

    void SizerMouseDown(object sender, MouseEventArgs e)
    {
        mov = true;
        My = MousePosition.Y;
        Mx = MousePosition.X;
        Sw = Width;
        Sh = Height;
    }

    void SizerMouseMove(object sender, MouseEventArgs e)
    {
        if (mov == true) {
            Width = MousePosition.X - Mx + Sw;
            Height = MousePosition.Y - My + Sh;
        }
    }

    void SizerMouseUp(object sender, MouseEventArgs e)
    {
        mov = false;
    }

1
一个不错的解决方案!不过我使用了一个小图片框来显示一个调整大小点图案的图像,将光标属性设置为“SizeAll”,这样当你在框上时,光标会变成调整大小的箭头。 - JonP

2

调整“表单”大小并移动它 >>> 完整代码 <<<<<

//首先,您需要添加此类

 class ReSize
     {

        private bool Above, Right, Under, Left, Right_above, Right_under, Left_under, Left_above;


        int Thickness=6;  //Thickness of border  u can cheang it
        int Area = 8;     //Thickness of Angle border 


        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="thickness">set thickness of form border</param>
        public ReSize(int thickness)
        {
            Thickness = thickness;
        }

        /// <summary>
        /// Constructor set thickness of form border=1
        /// </summary>
        public ReSize()
        {
            Thickness = 10;
        }

        //Get Mouse Position
        public  string getMosuePosition(Point mouse, Form form)
        {
            bool above_underArea = mouse.X > Area && mouse.X < form.ClientRectangle.Width - Area; /* |\AngleArea(Left_Above)\(=======above_underArea========)/AngleArea(Right_Above)/| */ //Area===>(==)
            bool right_left_Area = mouse.Y > Area && mouse.Y < form.ClientRectangle.Height - Area; 

            bool _Above=mouse.Y <= Thickness;  //Mouse in Above All Area
            bool _Right= mouse.X >= form.ClientRectangle.Width - Thickness;
            bool _Under=mouse.Y >= form.ClientRectangle.Height - Thickness;
            bool _Left=mouse.X <= Thickness;

            Above = _Above && (above_underArea); if (Above) return "a";   /*Mouse in Above All Area WithOut Angle Area */
            Right = _Right && (right_left_Area); if (Right) return "r";
            Under = _Under && (above_underArea); if (Under) return "u";
            Left = _Left && (right_left_Area);   if (Left) return "l";


            Right_above =/*Right*/ (_Right && (!right_left_Area)) && /*Above*/ (_Above && (!above_underArea));   if (Right_above) return "ra";     /*if Mouse  Right_above */
            Right_under =/* Right*/((_Right) && (!right_left_Area)) && /*Under*/(_Under && (!above_underArea));  if (Right_under) return "ru";     //if Mouse  Right_under 
            Left_under = /*Left*/((_Left) && (!right_left_Area)) && /*Under*/ (_Under && (!above_underArea));    if (Left_under) return "lu";      //if Mouse  Left_under
            Left_above = /*Left*/((_Left) && (!right_left_Area)) && /*Above*/(_Above && (!above_underArea));     if (Left_above) return "la";      //if Mouse  Left_above

            return "";

        }


    }
然后创建表单
 public partial class FormGDI : Form
    {

        ReSize resize = new ReSize();     // ReSize Class "/\" To Help Resize Form <None Style>


        public FormGDI()
        {
            InitializeComponent();
            this.SetStyle(ControlStyles.ResizeRedraw, true);

        }


        private const int cGrip = 16;      // Grip size
        private const int cCaption = 32;   // Caption bar height;

        protected override void OnPaint(PaintEventArgs e)
        {
            //this if you want to draw   (if)

            Color theColor = Color.FromArgb(10, 20, 20, 20);
            theColor = Color.DarkBlue;
            int BORDER_SIZE = 4;
            ControlPaint.DrawBorder(e.Graphics, ClientRectangle,
                                         theColor, BORDER_SIZE, ButtonBorderStyle.Dashed,
                                         theColor, BORDER_SIZE, ButtonBorderStyle.Dashed,
                                         theColor, BORDER_SIZE, ButtonBorderStyle.Dashed,
                                         theColor, BORDER_SIZE, ButtonBorderStyle.Dashed);


            Rectangle rc = new Rectangle(this.ClientSize.Width - cGrip, this.ClientSize.Height - cGrip, cGrip, cGrip);
            ControlPaint.DrawSizeGrip(e.Graphics, this.BackColor, rc);
            rc = new Rectangle(0, 0, this.ClientSize.Width, cCaption);
            e.Graphics.FillRectangle(Brushes.DarkBlue, rc);



            base.OnPaint(e);
        }


        //set MinimumSize to Form
        public override Size MinimumSize
        {
            get
            {
                return base.MinimumSize;
            }
            set
            {
                base.MinimumSize = new Size(179, 51); 
            }
        }

        //
        //override  WndProc  
        //
        protected override void WndProc(ref Message m)
        {
            //****************************************************************************

            int x = (int)(m.LParam.ToInt64() & 0xFFFF);               //get x mouse position
            int y = (int)((m.LParam.ToInt64() & 0xFFFF0000) >> 16);   //get y mouse position  you can gave (x,y) it from "MouseEventArgs" too
            Point pt = PointToClient(new Point(x, y));

            if (m.Msg == 0x84)
            {
                switch (resize.getMosuePosition(pt, this))
                {
                    case "l": m.Result = (IntPtr)10; return;  // the Mouse on Left Form
                    case "r": m.Result = (IntPtr)11; return;  // the Mouse on Right Form
                    case "a": m.Result = (IntPtr)12; return;
                    case "la": m.Result = (IntPtr)13; return;
                    case "ra": m.Result = (IntPtr)14; return;
                    case "u": m.Result = (IntPtr)15; return;
                    case "lu": m.Result = (IntPtr)16; return;
                    case "ru": m.Result = (IntPtr)17; return; // the Mouse on Right_Under Form
                    case "": m.Result = pt.Y < 32 /*mouse on title Bar*/ ? (IntPtr)2 : (IntPtr)1; return;  

                }
            }

              base.WndProc(ref m);

        }

    }

你能详细说明一下这个回答是如何解决问题的吗?谢谢! - DanM7
详细说明:首先,我会创建一个调整大小的类,它有一个方法。该方法通过计算(point mouse)和(Form form)来确定鼠标位置,并获取表单的宽度和高度。然后,最重要的是WndProc覆盖方法。此方法具有ref Message m参数,当m.msg=0x84值时,您可以设置m.result=10,这意味着您可以从左侧调整form的大小,而m.Result=11则从右侧调用form,以此类推到17。但是,当m.Result=2时,您可以调用移动form,而当m.Result=1时,表示不执行任何操作。 - NourAldienArabian
1
它有帮助,但是它不能处理滚动,当滚动时会在表单中创建新的边框“线”。 - CularBytes

1
最简单的方法是将鼠标事件分配给表单或标题栏,无论您想要移动哪个部分。 您可以通过将这些方法分配给它们的事件名称来移动无边框表单。
    int movX,movY;
    bool isMoving;

    private void onMouseDown(object sender, MouseEventArgs e)  
    {
         // Assign this method to mouse_Down event of Form or Panel,whatever you want
        isMoving = true;
        movX = e.X;
        movY = e.Y;
    }

    private void onMouseMove(object sender, MouseEventArgs e)
    {
         // Assign this method to Mouse_Move event of that Form or Panel
        if (isMoving)
        {
            this.SetDesktopLocation(MousePosition.X - movX, MousePosition.Y - movY);
        }
    }

    private void onMouseUp(object sender, MouseEventArgs e)
    {
       // Assign this method to Mouse_Up event of Form or Panel.
        isMoving = false;
    }

第二行的moxY应该替换为movY。 - Masuri

0
如果您不介意在顶部有一个短的工具栏,您可以使用“常规”的可调整大小的表单,将.ControlBox设置为false,并将.Text(顶部标题栏)设置为空字符串。这样,您就会得到一个可调整大小的窗体,看起来像是双击图表时出现的任务管理器。 这种方法的优点是,当您从左侧调整大小时,右边框不会抖动。同样地,当您从顶部调整大小时也是如此。
this.FormBorderStyle = FormBorderStyle.Sizable;
this.ControlBox = false;
this.Text = "";

-3
(1)FormBorderStyle = Sizable 或 SizableToolWindows 在此输入图像描述 (2)清除表单文本中的文字

enter image description here


将 ControlBox 属性设置为 false。 - mostafa rabee
1
你知道你可以编辑你的帖子来改进它,对吧? - Yunnosch

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接