做设计需要素材的常用网站,免费网站注册申请,网站建设大神级公司,专做韩餐网站最近要做个软件正在做技术准备#xff0c;由于WINFORM生成的窗体很丑陋#xff0c;一个好的软件除了功能性很重要外#xff0c;UI的体验也是不容忽视的。习惯性的在网上搜素了下#xff0c;换肤控件也有好几款#xff0c;但是有些用起来不是很好用#xff0c;好点的也要花…最近要做个软件正在做技术准备由于WINFORM生成的窗体很丑陋一个好的软件除了功能性很重要外UI的体验也是不容忽视的。习惯性的在网上搜素了下换肤控件也有好几款但是有些用起来不是很好用好点的也要花很多银子哦而且毕竟是别人写的心里总不是个滋味所以决定自己尝试着写写看花了一个晚上终于做出来了个DEMO貌似还不错贴图如下图片是直接是用的暴风影音的寒自己一个。。 下面和大家分享下。 首先分析下皮肤的制作原理我的理解是把整个窗体去边框后划分为9个区域如果有更复杂的界面可以划分更多有图有真相 然后准备皮肤素材切图我的切图如下 接着可以开工了 1.初始化图片资源变量 protected int formMinX 0;//最小化按钮的X坐标protected int formMaxX 0;//最大化按钮的X坐标protected int formCloseX 0;//关闭按钮的X坐标protected int formTitleMarginLeft 0;//标题栏的左边界protected int formTitleMarginRight 0;//标题栏的右边界Image imgTopLeft (Image)Resources.topleft;//窗体顶部左上角图片Image imgTopRight (Image)Resources.topright;//窗体顶部右上角图片Image imgTopMiddle (Image)Resources.topstretch;//窗体顶部中间图片Image imgBottomLeft (Image)Resources.bottomLeft;//窗体底部左下角图片Image imgBottonRight (Image)Resources.bottomRight;//窗体底部右下角图片Image imgBottonmMiddle (Image)Resources.bottomstretch;//窗体底部中间图片Image imgMiddleLeft (Image)Resources.LeftDrag_Mid;//窗体中部左边框图片Image imgMiddleRight (Image)Resources.RightDrag_Mid;//窗体中部右边框图片Image imgFormMin (Image)Resources.skin_btn_min;//最小化按钮Image imgFormMax (Image)Resources.skin_btn_max;//最大化按钮Image imgFormClose (Image)Resources.skin_btn_close;//关闭按钮Image imgFormRestore (Image)Resources.skin_btn_restore;//还原按钮 2.重写OnPaint事件。代码直接贴上来比较简单就是计算图片要绘制到窗体的坐标然后把图片绘到窗体上 protected override void OnPaint(PaintEventArgs e){base.OnPaint(e);this.BackColor Color.Black;//绘制皮肤Graphics g e.Graphics;//绘制窗体顶部左上角图片g.DrawImage(imgTopLeft, 0, 0, imgTopLeft.Width, imgTopLeft.Height);int topRightX e.ClipRectangle.Width - imgTopRight.Width;//绘制窗体顶部右上角图片g.DrawImage(imgTopRight, topRightX, 0, imgTopRight.Width, imgTopRight.Height);int topMiddleWidth e.ClipRectangle.Width - (imgTopLeft.Width imgTopRight.Width) 4;//绘制窗体顶部中间图片(标题栏)formTitleMarginLeft imgTopLeft.Width;formTitleMarginRight topRightX;g.DrawImage(imgTopMiddle, imgTopLeft.Width, 0, topMiddleWidth, imgTopMiddle.Height);//绘制窗体底部左下角图片g.DrawImage(imgBottomLeft, 0, e.ClipRectangle.Height - imgBottomLeft.Height, imgBottomLeft.Width, imgBottomLeft.Height);//绘制窗体底部右下角图片g.DrawImage(imgBottonRight, e.ClipRectangle.Width - imgBottomLeft.Width, e.ClipRectangle.Height - imgBottonRight.Height, imgBottonRight.Width, imgBottonRight.Height);//绘制窗体底部中间图片g.DrawImage(imgBottonmMiddle, imgBottomLeft.Width, e.ClipRectangle.Height - imgBottonmMiddle.Height, e.ClipRectangle.Width - (imgBottomLeft.Width imgBottomLeft.Width) 4, imgBottonmMiddle.Height);//画左右边框g.DrawImage(imgMiddleLeft, 0, imgTopLeft.Height, imgMiddleLeft.Width, e.ClipRectangle.Height - (imgTopLeft.Height imgBottomLeft.Height));g.DrawImage(imgMiddleRight, e.ClipRectangle.Width - imgMiddleRight.Width, imgTopRight.Height, imgMiddleRight.Width, e.ClipRectangle.Height - (imgTopLeft.Height imgBottomLeft.Height));//画右上角按钮最小化最大化关闭formMinX topRightX;g.DrawImage(imgFormMin, topRightX, 0, imgFormMin.Width, imgFormMin.Height);if (this.WindowState FormWindowState.Maximized){imgFormMax imgFormRestore;}elseimgFormMax (Image)Resources.skin_btn_max;formMaxX topRightX imgFormMin.Width;g.DrawImage(imgFormMax, topRightX imgFormMin.Width, 0, imgFormMax.Width, imgFormMax.Height);formCloseX topRightX imgFormMax.Width imgFormMin.Width;g.DrawImage(imgFormClose, topRightX imgFormMax.Width imgFormMin.Width, 0, imgFormClose.Width, imgFormClose.Height);} 3.当窗体大小发生变化的时候同样要重绘所以重写OnSizeChanged的事件 protected override void OnSizeChanged(EventArgs e){base.OnSizeChanged(e);Invalidate();//强制窗体重绘} OK这样就完成了皮肤的绘制。接下来我们解决的问题有 1.如何用鼠标拖拽改变无边框的大小 2.如何用鼠标移动无边框窗体 3.如何让绘制的最小化最大化关闭按钮执行操作响应事件 对于第1个问题拖拽改变无边框的大小可以重写消息处理函数WndProc除了这个我找不到其它好的方法了如果哪个朋友知道请告诉我一声 const int WM_NCHITTEST 0x0084;const int HTLEFT 10;const int HTRIGHT 11;const int HTTOP 12;const int HTTOPLEFT 13;const int HTTOPRIGHT 14;const int HTBOTTOM 15;const int HTBOTTOMLEFT 0x10;const int HTBOTTOMRIGHT 17;protected override void WndProc(ref Message m){base.WndProc(ref m);switch (m.Msg){case WM_NCHITTEST: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)HTTOPLEFT;else if (vPoint.Y ClientSize.Height - 5)m.Result (IntPtr)HTBOTTOMLEFT;else m.Result (IntPtr)HTLEFT;else if (vPoint.X ClientSize.Width - 5)if (vPoint.Y 5)m.Result (IntPtr)HTTOPRIGHT;else if (vPoint.Y ClientSize.Height - 5)m.Result (IntPtr)HTBOTTOMRIGHT;else m.Result (IntPtr)HTRIGHT;else if (vPoint.Y 5)m.Result (IntPtr)HTTOP;else if (vPoint.Y ClientSize.Height - 5)m.Result (IntPtr)HTBOTTOM;break;}} 第2个问题鼠标移动无边框窗体网上一般有三种方法详见[转]C#无边框窗体移动的三种方法 其中有两种是用WINDOWS消息机制来完成但是我发现如果用消息机制来处理会造成鼠标的双击或者单击事件不能使用这一点让我很纠结所以就采用了最原始的处理方式。 private Point mouseOffset; //记录鼠标指针的坐标private bool isMouseDown false; //记录鼠标按键是否按下private void Main_MouseDown(object sender, MouseEventArgs e){if (e.Button MouseButtons.Left){mouseOffset new Point(-e.X, -e.Y);isMouseDown true;}} private void Main_MouseUp(object sender, MouseEventArgs e){if (e.Button MouseButtons.Left){isMouseDown false;}}private void Main_MouseMove(object sender, MouseEventArgs e){if (isMouseDown){Point mousePos Control.MousePosition;mousePos.Offset(mouseOffset.X, mouseOffset.Y);Location mousePos;}} 第3个问题我的思路是处理鼠标单击事件这就是为什么我放弃了用消息处理机制来解决问题2根据鼠标的坐标位置判断是在点击哪个图片来触发对应的事件 private void Main_MouseClick(object sender, MouseEventArgs e){//判断鼠标是否点的是右上角按钮区域if (e.X formMinX e.X formMinX Resources.skin_btn_min.Width e.Y imgFormMin.Height){this.WindowState FormWindowState.Minimized;}if (e.X formMaxX e.X formMaxX Resources.skin_btn_max.Width e.Y imgFormMax.Height){if (this.WindowState ! FormWindowState.Maximized)this.WindowState FormWindowState.Maximized;elsethis.WindowState FormWindowState.Normal;}if (e.X formCloseX e.X formCloseX Resources.skin_btn_close.Width e.Y imgFormClose.Height){Application.Exit();}} 然后最后的问题就是解决双击“标题栏”来最大化或者还原窗体了我的思路是在绘制窗体的时候就记录标题栏的边界坐标值然后在双击事件中根据鼠标的坐标位置来判断触发最大化还原事件。 private void Main_MouseDoubleClick(object sender, MouseEventArgs e){if (e.X formTitleMarginLeft e.X formTitleMarginRight e.Y imgTopMiddle.Height){if (this.WindowState ! FormWindowState.Maximized)this.WindowState FormWindowState.Maximized;elsethis.WindowState FormWindowState.Normal;}} OK整个皮肤的制作基本就完成了乍一看貌似基本功能都实现了但是如果想实现动态换肤还是很麻烦的下篇文章我会给出个动态换肤的解决方案和实现源码。 就这样了欢迎拍砖。源码下载 转载于:https://www.cnblogs.com/haiyabtx/archive/2012/09/21/2697190.html