Winform中实现拖动 Windows 边缘来调整其大小
https://blog.csdn.net/weixin_39829336/category_11687560.html
Winform中实现无边框窗体只需要设置一个属性FormBorderStyle = FormBorderStyle.None;即可,或者在设计器中直接设置。无边框表单的结果是丢失了标题栏和控制框(最小化、最大值和关闭按钮)。如果没有标题栏,则无法拖动和移动窗口。如果没有边框,则无法拖动 Windows 边缘来调整其大小。移动表单非常简单,但边缘拖动调整大小有点棘手。
下面通过监听鼠标事件和调整光标形状,实现了一个用户可以通过拖拽窗体边缘来调整窗体大小的功能。同时,它还确保了当鼠标离开窗体时,光标形状会恢复为默认的箭头形状。
先上效果图

具体来说,它允许用户通过拖动鼠标来改变窗体的大小。以下是代码的工作原理概述:
1.初始化:
在构造函数 Form1() 中,为 Form1 实例注册了两个事件处理器:MouseMove 用于处理鼠标移动时的行为,MouseLeave 用于处理鼠标离开窗体时的行为。
2.鼠标移动处理 (Main_MouseMove):
如果鼠标接近右下角,则显示双向对角线箭头。
如果鼠标接近右侧,则显示水平箭头。
如果鼠标接近底部,则显示垂直箭头。
Cursors.SizeNWSE: 允许同时改变窗体的宽度和高度。
Cursors.SizeWE: 只允许改变窗体的宽度。
Cursors.SizeNS: 只允许改变窗体的高度。
当鼠标在窗体内移动时,会触发 MouseMove 事件。
如果鼠标左键被按下,并且光标形状是某种尺寸调整箭头(Cursors.SizeNWSE, Cursors.SizeWE, 或 Cursors.SizeNS),则根据当前光标类型调整窗体的宽度和/或高度。
根据鼠标位置与窗体边缘的距离(5像素内),动态地改变光标形状以提示用户可以进行何种类型的尺寸调整:
如果鼠标不在这些区域,则恢复默认的箭头光标。
3.鼠标离开窗体处理 (Main_Leave):
当鼠标指针离开窗体范围时,将光标恢复到默认的箭头状态。
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Runtime.InteropServices; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; namespace WindowsFormsApp7 { public partial class Form1 : Form { private int borderSize = 2; [DllImport("user32.DLL", EntryPoint = "ReleaseCapture")] private extern static void ReleaseCapture(); [DllImport("user32.DLL", EntryPoint = "SendMessage")] private static extern void SendMessage(System.IntPtr hWnd, int wMsg, int wParam, int lParam); private void panelTitleBar_MouseDown(object sender, MouseEventArgs e) //panel的MouseDown事件 { ReleaseCapture(); SendMessage(this.Handle, 0x112, 0xf012, 0); } public Form1() { InitializeComponent(); this.Padding = new Padding(borderSize); this.BackColor = Color.FromArgb(245, 245, 255); //98, 102, 244);// this.ControlBox = false; this.Text = string.Empty; this.FormBorderStyle = FormBorderStyle.None; //this.WindowState = FormWindowState.Maximized; this.MaximizedBounds = Screen.FromHandle(this.Handle).WorkingArea; MouseMove += Main_MouseMove; MouseLeave += Main_Leave; // 有控件在边缘时,处理一下更好一些 } private void Form1_Load(object sender, EventArgs e) { this.panelMenu.Width = 180; } #region 退出按钮 private void appExit(object sender, EventArgs e) { //退出按钮 Application.Exit(); } #endregion #region 最大化按钮 private void butMax_Click(object sender, EventArgs e) { //最大化按钮 if (this.WindowState == FormWindowState.Normal) { this.WindowState = FormWindowState.Maximized; } else { this.WindowState = FormWindowState.Normal; } } #endregion #region 最小化按钮 private void butMin_Click(object sender, EventArgs e) { //最小化按钮 this.WindowState = FormWindowState.Minimized; } #endregion #region 侧面菜单栏折叠与展开 //private void CollapseMenu() //{ // if (this.panel1.Width > 50) // { // this.panel1.Width = 50; // this.pictureBox1.Visible = false; // //this.button7.Dock = DockStyle.Fill; // foreach (Button control in panel1.Controls.OfType<Button>()) // { // control.Text = ""; // control.ImageAlign = ContentAlignment.MiddleCenter; // control.Padding = new Padding(0); // } // } // else // { // this.panel1.Width = 180; // this.pictureBox1.Visible = true; // //this.button7.Dock = DockStyle.Right; // foreach (Button control in panel1.Controls.OfType<Button>()) // { // control.Text = control.Tag.ToString(); // control.ImageAlign = ContentAlignment.MiddleLeft; // control.Padding = new Padding(45, 0, 0, 0); // } // } //} private void CollapseMenu() { //这段C#代码实现了一个CollapseMenu()方法,用于控制侧边栏菜单的折叠和展开 //首先判断当前侧边栏的宽度是否大于200,如果是,则将宽度设置为100,隐藏图标, //将菜单按钮的Dock属性设置为Top, //设置面板的内边距为上边10像素,下左右为0, //并遍历所有的菜单按钮,将它们的文本设置为空, //图像对齐方式设置为居中,内边距设置为0。 //如果当前侧边栏的宽度小于等于200, //就将宽度设置为260,显示图标,将菜单按钮的Dock属性设置为None, //设置面板的内边距为上下左右都为0, //并遍历所有的菜单按钮,将它们的文本设置为按钮的Tag属性值前面加两个空格, //图像对齐方式设置为左对齐,文本对齐方式设置为右对齐, //按钮文本和图像的相对位置设置为文本在图像左侧, //内边距设置为上0像素,左边距为10像素,下右边距为0。 if (this.panelMenu.Width > 100) { panelMenu.Width = 50; iconPictureBox1.Visible = false; //btnMenu.Dock = DockStyle.Top; //this.panelMenu.Padding = new Padding(0, 10, 0, 0); foreach (var mybutton in this.panelMenu.Controls.OfType<Button>()) //筛选出panelMenu内所有属于Button类型的子控件 { mybutton.Text = ""; mybutton.ImageAlign = ContentAlignment.MiddleCenter; //将其图像对齐方式设置为居中对齐 mybutton.Padding = new Padding(0); //内边距设为0 } } else { panelMenu.Width = 180; iconPictureBox1.Visible = true; //btnMenu.Dock = DockStyle.None; //this.panelMenu.Padding = new Padding(0, 0, 0, 0); foreach (var mybutton in this.panelMenu.Controls.OfType<Button>()) //筛选出panelMenu内所有属于Button类型的子控件 { mybutton.Text =mybutton.Tag.ToString(); //将控件的Tag赋值给Text " " + mybutton.ImageAlign = ContentAlignment.MiddleLeft; mybutton.TextAlign = ContentAlignment.MiddleRight; mybutton.TextImageRelation = TextImageRelation.ImageBeforeText; //Text和Image位置关系 mybutton.Padding = new Padding(30, 0, 0, 0); } } } //侧面菜单栏折叠与展开 private void btnMenu_Click(object sender, EventArgs e) { CollapseMenu(); } #endregion #region 保持整体布局不变 private void AdjustForm() { switch (this.WindowState) { case FormWindowState.Normal: if (this.Padding.Top != borderSize) this.Padding = new Padding(borderSize); break; case FormWindowState.Minimized: this.Padding = new Padding(8, 8, 8, 8); break; case FormWindowState.Maximized: break; default: break; } } private void Form1_Resize(object sender, EventArgs e) { AdjustForm(); } #endregion #region 控制无边框拉伸 private void Main_MouseMove(object sender, MouseEventArgs e) { if (e.Button == MouseButtons.Left)//左键按下移动,拖拽调整大小 { // MousePosition的参考点是屏幕的左上角,表示鼠标当前相对于屏幕左上角的坐标。this.Left和this.Top的参考点也是屏幕 if (Cursor == Cursors.SizeNWSE) // 倾斜拖拽 { // 改变窗体宽和高的代码,其宽高为鼠标屏幕位置减去窗体的Left,Top距离 this.Width = MousePosition.X - this.Left; this.Height = MousePosition.Y - this.Top; } else if (Cursor == Cursors.SizeWE) // 水平拖拽 { Width = MousePosition.X - this.Left; } else if (Cursor == Cursors.SizeNS) // 垂直拖拽 { Height = MousePosition.Y - this.Top; } } //鼠标移动过程中,坐标时刻在改变 //当鼠标移动时横坐标距离窗体右边缘5像素以内且纵坐标距离下边缘也在5像素以内时,要将光标变为倾斜的箭头形状 if (e.Location.X >= this.Width - 5 && e.Location.Y > this.Height - 5) { this.Cursor = Cursors.SizeNWSE; // 右下角 双向对角线光标 } //当鼠标移动时横坐标距离窗体右边缘5像素以内时,要将光标变为双向水平箭头形状 else if (e.Location.X >= this.Width - 5) { this.Cursor = Cursors.SizeWE; // 双向水平光标 } //当鼠标移动时纵坐标距离窗体下边缘5像素以内时,要将光标变为垂直水平箭头形状 else if (e.Location.Y >= this.Height - 5) { this.Cursor = Cursors.SizeNS; // 双向垂直光标 } //否则,以外的窗体区域,鼠标星座均为单向箭头(默认) else this.Cursor = Cursors.Arrow; } private void Main_Leave(object sender, EventArgs e) { Cursor = Cursors.Arrow;// 移出窗体变为正常 } #endregion } }
通过这种方式,当用户将鼠标悬停在窗体边缘并拖动时,窗体会相应地改变其大小,提供了直观的用户体验。这段代码没有涉及到实际的拖动整个窗体的位置,仅关注于改变窗体的尺寸。如果需要实现窗体位置的拖动,还需要额外的逻辑来处理标题栏或其他指定区域的拖动行为。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步