本人新手,想写个上位机,窗口能够实现最小化,最大化,拖动,改变大小等常用功能,Winform窗体的FormBorderStyle设置成sizable即可实现,但是窗体有自带的边框,不好看且无法编辑,想去掉,网上查到几种方法,都尝试了,但是都有缺陷,不太满意,不过最终还是实现了。走了弯路,浪费了不少时间,在这分享一下,最后效果是没有冗余边框,菜单栏在顶部
网上查到有两个方法(方法一和方法二),都需要将FormBorderStyle设置成None,首先说一下窗体的最小化最大化关闭,以及移动,然后是太多嵌套表格后防止闪烁,最后是窗体缩放,可以按目录自取。
目录
窗体最大化最小化和关闭
窗体移动
解决闪烁问题
缩放
方法一
方法二
方法三
方法四
完整代码
窗体最大化最小化和关闭
这个简单,直接放三个button,改背景图片,实现相应功能
private void buttonClose_Click(object sender, EventArgs e){this.Close(); //关闭窗口}private void buttonMax_Click(object sender, EventArgs e){if (this.WindowState == FormWindowState.Maximized) //如果处于最大化,则还原{this.WindowState = FormWindowState.Normal;Image backImage = Resources.最大化;buttonMax.BackgroundImage = backImage;}else{this.WindowState = FormWindowState.Maximized; //如果处于普通状态,则最大化Image backImage = Resources.还原;buttonMax.BackgroundImage = backImage;}}private void buttonMin_Click(object sender, EventArgs e){this.WindowState = FormWindowState.Minimized; //最小化}private void Form1_SizeChanged(object sender, EventArgs e){if (this.WindowState != FormWindowState.Maximized)buttonMax.BackgroundImage = Resources.最大化;}
最后的Form1_SizeChanged的作用:当窗体最大化时,拖动窗体顶部窗体会变小,但是这种情况下最大化按钮的图标还是还原图标,所以写个方法刷新一下
点击最大化按钮后会发现窗体变大后覆盖了整个屏幕,把任务栏都遮住了,解决这个问题的方法如下:
//在窗体的Load事件中编写private void Form1_Load(object sender, EventArgs e){this.MaximizedBounds = Screen.PrimaryScreen.WorkingArea;}
图标可以到这里下载 :iconfont-阿里巴巴矢量图标库/search/index?searchType=icon&q=close&page=1&fills=&tag=&fromCollection=1
窗体移动
我这里设置的是鼠标在菜单栏上按下时可以拖动,网上方法很多,下面这个是我认为最简单的
//窗体移动[DllImport("user32.dll")]public static extern bool ReleaseCapture();[DllImport("user32.dll")]public static extern bool SendMessage(IntPtr hwnd, int wMsg, int wParam, int lParam);private void menuStrip1_MouseDown(object sender, MouseEventArgs e){if (e.Clicks == 1){//窗体移动if (e.Button == MouseButtons.Left){ReleaseCapture(); //释放鼠标捕捉//发送左键点击的消息至该窗体(标题栏)SendMessage(this.Handle, 0xA1, 0x02, 0);}}}
虽然不懂原理是啥,但是好用哈哈哈
参考文章:winform自定义最大化 - CSDN/tags/MtTaAgzsNjk5ODYtYmxvZwO0O0OO0O0O.html
解决闪烁问题
为了让窗体在改变大小时各个部分能够更合理的自动分布,设计时用了很多表格,表格嵌套多了最大化最小化以及缩放窗体时就容易出现闪烁的情况,网上也有较多方法,下面这个是我试了之后有效果的
代码:
protected override CreateParams CreateParams //防止改变窗口大小时控件闪烁{get{CreateParams cp = base.CreateParams;cp.ExStyle |= 0x02000000; // Turn on WS_EX_COMPOSITEDreturn cp;}}
参考文章:(1条消息) Winfrom窗体由于控件过多而闪烁的解决方法_路漫漫都是坑的博客-CSDN博客_winform 最大化 闪烁/qq_25465525/article/details/88739837?utm_medium=distribute.pc_relevant.none-task-blog-2~default~baidujs_baidulandingword~default-5-88739837-blog-117190950.pc_relevant_paycolumn_v3&spm=1001.2101.3001.4242.4&utm_relevant_index=8
补充说明:
FormBorderStyle设置成None,且添加了防闪烁代码后,最大化最小化窗口会显示不全,可以通过在Form1_SizeChanged方法中添加两个refersh()可以解决,但是视觉效果不好
private void Form1_SizeChanged(object sender, EventArgs e){if (this.WindowState != FormWindowState.Maximized)buttonMax.BackgroundImage = Resources.最大化;refresh();refresh();}
缩放
方法一
自己编写程序,主要通过MouseDown,MouseUp,MouseMove三个方法和自定义ResizeWindow方法实现根据鼠标位置判断和实施对应的窗体缩放。
//窗体改变大小private bool isMouseDown = false; //表示鼠标当前是否处于按下状态,初始值为否 MouseDirection direction = MouseDirection.None; //表示拖动的方向,起始为None,表示不拖动//private Point mPoint; //鼠标坐标private bool changeornot = false; //是否是改变窗体大小,true为是,false为不是//定义一个枚举,表示拖动方向,用于判断public enum MouseDirection{HerizontalLeft, //水平方向拖动,只改变窗体的宽度HerizontalRight,VerticalTop, //垂直方向拖动,只改变窗体的高度 VerticalBottom,DecliningLefttop, //倾斜方向,同时改变窗体的宽度和高度DecliningLeftbottom,DecliningRighttop,DecliningRightbottom,None //不做标志,即不拖动窗体改变大小}//鼠标在窗体内按下时获取鼠标的位置,并设置按下状态为真private void Form1_MouseDown(object sender, MouseEventArgs e){//mPoint = new Point(e.X, e.Y);isMouseDown = true;}// 鼠标弹起,不再改变窗体尺寸private void Form1_MouseUp(object sender, MouseEventArgs e){isMouseDown = false;direction = MouseDirection.None;}//鼠标移动过程中,坐标时刻在改变,根据不同位置改变拖动方向、鼠标样式和changeornot的状态private void Form1_MouseMove(object sender, MouseEventArgs e){if (isMouseDown && direction != MouseDirection.None) //满足条件则直接执行改变窗口大小的方法{ResizeWindow();return;}//当鼠标移动时横坐标距离窗体左边缘5像素以内且纵坐标距离上边缘也在5像素以内时if (e.Location.X <= 5 && e.Location.Y <= 5){this.Cursor = Cursors.SizeNWSE; //光标变为右下倾斜的箭头形状\direction = MouseDirection.DecliningLefttop;changeornot = true;}//左下else if (e.Location.X <= 5 && e.Location.Y >= this.Height - 5){this.Cursor = Cursors.SizeNESW; //光标变为右上倾斜的箭头形状/direction = MouseDirection.DecliningLeftbottom;changeornot = true;}//右上else if (e.Location.X >= this.Width - 5 && e.Location.Y <= 5){this.Cursor = Cursors.SizeNESW; //光标变为右上倾斜的箭头形状/direction = MouseDirection.DecliningRighttop;changeornot = true;}//右下else if (e.Location.X >= this.Width - 5 && e.Location.Y > this.Height - 5){this.Cursor = Cursors.SizeNWSE; //光标变为右下倾斜的箭头形状\direction = MouseDirection.DecliningRightbottom;changeornot = true;}//左else if (e.Location.X <= 5){this.Cursor = Cursors.SizeWE; //将光标变为水平的箭头形状direction = MouseDirection.HerizontalLeft;changeornot = true;}//右else if (e.Location.X >= this.Width - 5){this.Cursor = Cursors.SizeWE; //将光标变为水平的箭头形状direction = MouseDirection.HerizontalRight;changeornot = true;}//上else if (e.Location.Y <= 1){this.Cursor = Cursors.SizeNS; //将光标变为竖直的箭头形状direction = MouseDirection.VerticalTop;changeornot = true;}//下else if (e.Location.Y >= this.Height - 5){this.Cursor = Cursors.SizeNS; //将光标变为竖直的箭头形状direction = MouseDirection.VerticalBottom;changeornot = true;}//否则,其他窗体区域,鼠标星座均为单向箭头(默认)else{this.Cursor = Cursors.Arrow;direction = MouseDirection.None;changeornot = false;}}private void ResizeWindow(){//MousePosition的参考点是屏幕的左上角,表示鼠标当前相对于屏幕左上角的坐标。//this.left和this.top的参考点也是屏幕,属性MousePosition是程序的重点if (direction == MouseDirection.DecliningLefttop) //左上{this.Cursor = Cursors.SizeNWSE; //光标为右下倾斜的箭头形状\this.Width = this.Right - MousePosition.X; //改变窗体宽和高this.Height = this.Bottom - MousePosition.Y;this.Location = new Point(MousePosition.X, MousePosition.Y); //改变窗体位置}else if (direction == MouseDirection.DecliningLeftbottom) //左下{this.Cursor = Cursors.SizeNESW;this.Location = new Point(MousePosition.X, this.Top);this.Width = this.Right - MousePosition.X;this.Height = MousePosition.Y - this.Top;}else if (direction == MouseDirection.DecliningRighttop) //右上{this.Cursor = Cursors.SizeNESW;this.Location = new Point(this.Left, MousePosition.Y);this.Width = MousePosition.X - this.Left;this.Height = this.Bottom - MousePosition.Y;}else if (direction == MouseDirection.DecliningRightbottom) //右下{this.Cursor = Cursors.SizeNWSE; //不改变窗体位置this.Width = MousePosition.X - this.Left;this.Height = MousePosition.Y - this.Top;}else if (direction == MouseDirection.HerizontalLeft) //左{this.Cursor = Cursors.SizeWE;this.Location = new Point(MousePosition.X, this.Top);this.Width = this.Right - MousePosition.X;}else if (direction == MouseDirection.HerizontalRight) //右{this.Cursor = Cursors.SizeWE;this.Width = MousePosition.X - this.Left;}else if (direction == MouseDirection.VerticalTop) //上{this.Cursor = Cursors.SizeNS;this.Location = new Point(this.Left, MousePosition.Y);this.Height = this.Bottom - MousePosition.Y;}else if (direction == MouseDirection.VerticalBottom) //下{this.Cursor = Cursors.SizeNS;this.Height = MousePosition.Y - this.Top;}//即使鼠标按下,但是不在窗口右和下边缘,那么也不能改变窗口大小else{this.Cursor = Cursors.Arrow;}}
实际效果是能缩放,但是闪烁卡顿严重
参考文章:(1条消息) winform无边框在panel上拖动窗口位置,改变窗口大小_傲娇萌主的博客-CSDN博客_winform窗体可拖动变大小属性/qq_37341685/article/details/12227
winform 设置无边框后的窗口大小调整 - 知乎 ()/p/505185678
方法二
直接上代码
//窗体缩放const int Guying_HTLEFT = 10;const int Guying_HTRIGHT = 11;const int Guying_HTTOP = 12;const int Guying_HTTOPLEFT = 13;const int Guying_HTTOPRIGHT = 14;const int Guying_HTBOTTOM = 15;const int Guying_HTBOTTOMLEFT = 0x10;const int Guying_HTBOTTOMRIGHT = 17;protected override void WndProc(ref Message m){switch (m.Msg){case 0x0084:base.WndProc(ref m);Point vPoint = new Point((int)m.LParam & 0xFFFF,(int)m.LParam >> 16 & 0xFFFF);vPoint = PointToClient(vPoint);if (vPoint.X <= 5)if (vPoint.Y <= 5)m.Result = (IntPtr)Guying_HTTOPLEFT;else if (vPoint.Y >= ClientSize.Height - 5)m.Result = (IntPtr)Guying_HTBOTTOMLEFT;else m.Result = (IntPtr)Guying_HTLEFT;else if (vPoint.X >= ClientSize.Width - 5)if (vPoint.Y <= 5)m.Result = (IntPtr)Guying_HTTOPRIGHT;else if (vPoint.Y >= ClientSize.Height - 5)m.Result = (IntPtr)Guying_HTBOTTOMRIGHT;else m.Result = (IntPtr)Guying_HTRIGHT;else if (vPoint.Y <= 2)m.Result = (IntPtr)Guying_HTTOP;else if (vPoint.Y >= ClientSize.Height - 5)m.Result = (IntPtr)Guying_HTBOTTOM;break;default:base.WndProc(ref m);break;}}
其方法与一类似,通过判断鼠标位置实施不同缩放,但是缩放的方法不是自己写的,这个方法缩放会流畅很多,和有边框的窗口差不多,但是因为FormBorderStyle设置成None,没有边框,缩放过程中部分控件又会轻微闪烁(有防闪烁代码的基础上)。一般使用边框附近5个像素,因为我的菜单栏距顶部只有两个像素,设置成5会失效,所以上方缩放我设置的2 (else if (vPoint.Y <= 2))
Winform自定义无边框窗体 - landptf - 博客园 ()/landptf/p/5068523.html
方法三
设置FormBorderStyle设置成Sizable,但是窗口样式中controlbox设置成false,且Form1的Text设置为空,效果如下。这样能够拥有边框的缩放功能,没有一点卡顿和闪烁,但是顶端有一个白色窄边,其他三边没有,但是最大化窗口时其他三边会有缝隙,也就是说边框虽然不显示,但还是在。
方法四
此方法可以说是完美解决问题,经过方法二和方法三的折腾,我发现可以将窗口的FormBorderStyle设置成FixedSingle(3D也行,看个人审美),然后controlbox设置成false,且Text设置为空,此时窗口拥有系统的边框,不占位置,能够使用系统自带窗体的功能(比如点击任务栏图标可以最小化和还原),且显示正常(最大化最小化不会有显示缺陷),但是窗口不能缩放,再将方法二的代码加上,就完美解决了
适合新手使用
完整代码(需要按照方法四设置窗体)
#region 窗体设置private void buttonClose_Click(object sender, EventArgs e){this.Close(); //关闭窗口}private void buttonMax_Click(object sender, EventArgs e){if (this.WindowState == FormWindowState.Maximized) //如果处于最大化,则还原{this.WindowState = FormWindowState.Normal;Image backImage = Resources.最大化;buttonMax.BackgroundImage = backImage;}else{this.WindowState = FormWindowState.Maximized; //如果处于普通状态,则最大化Image backImage = Resources.还原;buttonMax.BackgroundImage = backImage;}}private void buttonMin_Click(object sender, EventArgs e){this.WindowState = FormWindowState.Minimized; //最小化}private void Form1_SizeChanged(object sender, EventArgs e){if (this.WindowState != FormWindowState.Maximized)buttonMax.BackgroundImage = Resources.最大化;}protected override CreateParams CreateParams //防止改变窗口大小时控件闪烁{get{CreateParams cp = base.CreateParams;cp.ExStyle |= 0x02000000; // Turn on WS_EX_COMPOSITEDreturn cp;}}//窗体移动[DllImport("user32.dll")]public static extern bool ReleaseCapture();[DllImport("user32.dll")]public static extern bool SendMessage(IntPtr hwnd, int wMsg, int wParam, int lParam);private void menuStrip1_MouseDown(object sender, MouseEventArgs e){if (e.Clicks == 1){//窗体移动if (e.Button == MouseButtons.Left){ReleaseCapture(); //释放鼠标捕捉//发送左键点击的消息至该窗体(标题栏)SendMessage(this.Handle, 0xA1, 0x02, 0);}}}//窗体缩放const int Guying_HTLEFT = 10;const int Guying_HTRIGHT = 11;const int Guying_HTTOP = 12;const int Guying_HTTOPLEFT = 13;const int Guying_HTTOPRIGHT = 14;const int Guying_HTBOTTOM = 15;const int Guying_HTBOTTOMLEFT = 0x10;const int Guying_HTBOTTOMRIGHT = 17;protected override void WndProc(ref Message m){switch (m.Msg){case 0x0084:base.WndProc(ref m);Point vPoint = new Point((int)m.LParam & 0xFFFF,(int)m.LParam >> 16 & 0xFFFF);vPoint = PointToClient(vPoint);if (this.WindowState != FormWindowState.Normal)break; //源代码在窗体最大化状态下,鼠标移到窗口边缘也会出现拖动标识,添加这句代码可以避免if (vPoint.X <= 5)if (vPoint.Y <= 5)m.Result = (IntPtr)Guying_HTTOPLEFT;else if (vPoint.Y >= ClientSize.Height - 5)m.Result = (IntPtr)Guying_HTBOTTOMLEFT;else m.Result = (IntPtr)Guying_HTLEFT;else if (vPoint.X >= ClientSize.Width - 5)if (vPoint.Y <= 5)m.Result = (IntPtr)Guying_HTTOPRIGHT;else if (vPoint.Y >= ClientSize.Height - 5)m.Result = (IntPtr)Guying_HTBOTTOMRIGHT;else m.Result = (IntPtr)Guying_HTRIGHT;else if (vPoint.Y <= 2)m.Result = (IntPtr)Guying_HTTOP;else if (vPoint.Y >= ClientSize.Height - 5)m.Result = (IntPtr)Guying_HTBOTTOM;break;default:base.WndProc(ref m);break;}}#endregion