我想做一位狂热的程序猿粪子!
其实一直都很想做点什么,工作原因林林种种导致停止了前进的脚步。
有时会为自己的一个目标狂热,但经常发觉激情过后更多的总是为自己找借口!
最近感觉奔三将近。逐有感而发,不能再这样下去了。
即拿出以前自己为那狂热好一阵的东西继续下去。
一直想为自己开发一套控件库,但感觉精力确实有限,也没那么多时间,逐渐浇灭了这样的织热。
这是套窗体皮肤,断断续续所花费的时间也不少。
下面我介绍下我的这套皮肤,其实也算不上一套,只算是个开始吧。
有人可能会想这不就是边框隐藏再绘制客户区么,这是目前大部人会选择的方案。但我这是连同客户区和边框一同绘的效果。
这种实现方式难度大些,更关键的是比较耗时,加之当时对有些消息的不了解,在一些问题上花费了大量的时间。
废话不多说帖代码
protected virtual void OnNcPaint(PaintEventArgs e) { Graphics dc = e.Graphics; dc.PageUnit = GraphicsUnit.Pixel; Rectangle iconArea = new Rectangle(10, 4, this.Icon.Width, this.Icon.Height); if (this.ShowIcon && iconArea.IntersectsWith(e.ClipRectangle)) dc.DrawIcon(this.Icon, new Rectangle(0, 0, this.IconSize.Width, this.IconSize.Height)); Rectangle textArea = this.CaptionArea; if (textArea.IntersectsWith(e.ClipRectangle)) { StringFormat strFmt = new StringFormat(); switch (this.CaptionAlign) { case ContentAlignment.TopLeft: strFmt.Alignment = StringAlignment.Near; strFmt.LineAlignment = StringAlignment.Near; if (this.ShowIcon) textArea.X += this.IconSize.Width; textArea.X += this.CaptionOffset.X; textArea.Y += this.captionOffset.Y; break; case ContentAlignment.TopCenter: strFmt.Alignment = StringAlignment.Center; strFmt.LineAlignment = StringAlignment.Near; break; case ContentAlignment.TopRight: strFmt.Alignment = StringAlignment.Far; strFmt.LineAlignment = StringAlignment.Near; textArea.Width = this.CaptionButtonOffset; textArea.Width -= this.CaptionOffset.X; textArea.Height -= this.CaptionOffset.Y; break; case ContentAlignment.MiddleLeft: strFmt.Alignment = StringAlignment.Near; strFmt.LineAlignment = StringAlignment.Center; if (this.ShowIcon) textArea.X += this.IconSize.Width; textArea.X += this.CaptionOffset.X; textArea.Y += this.captionOffset.Y; break; case ContentAlignment.MiddleCenter: strFmt.Alignment = StringAlignment.Center; strFmt.LineAlignment = StringAlignment.Center; break; case ContentAlignment.MiddleRight: strFmt.Alignment = StringAlignment.Far; strFmt.LineAlignment = StringAlignment.Center; textArea.Width = this.CaptionButtonOffset; break; case ContentAlignment.BottomLeft: strFmt.Alignment = StringAlignment.Near; strFmt.LineAlignment = StringAlignment.Far; if (this.ShowIcon) textArea.X += this.IconSize.Width; textArea.X += this.CaptionOffset.X; textArea.Y += this.captionOffset.Y; break; case ContentAlignment.BottomCenter: strFmt.Alignment = StringAlignment.Center; strFmt.LineAlignment = StringAlignment.Far; break; case ContentAlignment.BottomRight: strFmt.Alignment = StringAlignment.Far; strFmt.LineAlignment = StringAlignment.Far; textArea.Width = this.CaptionButtonOffset; textArea.Width -= this.CaptionOffset.X; textArea.Height -= this.CaptionOffset.Y; break; } using (SolidBrush brush = new SolidBrush(this.ForeColor)) { //dc.DrawString(this.Text, this.Font, brush, textArea, strFmt); TextDraw.DrawWordArtEffect(dc, this.Text, this.Font, this.ForeColor, Color.Black, textArea, strFmt, WordArtEffectStyle.shadow); } } }
protected override void OnPaintBackground(PaintEventArgs e) { //透明画刷填充 if (this.backgroundPattern == null) { this.backgroundPattern = DrawWinBackgroundPattern(); } e.Graphics.DrawImage(this.backgroundPattern, e.ClipRectangle, new Rectangle(e.ClipRectangle.X, this.CaptionHeight + e.ClipRectangle.Y, e.ClipRectangle.Width, e.ClipRectangle.Height), GraphicsUnit.Pixel); } protected override void WndProc(ref Message m) { switch ((WindowsMessages)m.Msg) { case WindowsMessages.WM_NCCALCSIZE: this.WmNcCalcSize(ref m); return; case WindowsMessages.WM_NCACTIVATE: this.WmNcActivate(ref m); return; case WindowsMessages.WM_NCUAHDRAWCAPTION: return; case WindowsMessages.WM_NCUAHDRAWFRAME: return; case WindowsMessages.WM_NCPAINT: this.WmNcPaint(ref m); return; case WindowsMessages.WM_NCHITTEST: this.WmNcHitTest(ref m); return; case WindowsMessages.WM_NCLBUTTONDBLCLK: if (this.MaximizeBox && this.MaximumSize.IsEmpty) base.WndProc(ref m); return; case WindowsMessages.WM_NCLBUTTONDOWN: this.WmNcLButtonDown(ref m); return; case WindowsMessages.WM_NCLBUTTONUP: this.WmNcLButtonUP(ref m); return; case WindowsMessages.WM_NCMOUSEMOVE: this.WmNcMouseMove(ref m); return; case WindowsMessages.WM_NCMOUSELEAVE: this.WmNcMouseLeave(ref m); return; case WindowsMessages.WM_LBUTTONDOWN: this.WmLButtonDown(ref m); return; case WindowsMessages.WM_GETMINMAXINFO: this.WmGetMinMaxInfo(ref m); return; default: base.WndProc(ref m); return; } }
protected virtual Image DrawWinBackgroundPattern() { Bitmap img = new Bitmap(this.Width, this.Height); using (Graphics gp = Graphics.FromImage(img)) { gp.SmoothingMode = SmoothingMode.AntiAlias; gp.PageUnit = GraphicsUnit.Pixel; gp.Clear(this.BackColor); if (this.BackgroundImage == null) { using (LinearGradientBrush brush = new LinearGradientBrush(this.CaptionArea, ColorDraw.ColorOffset(this.BackColor, 30), Color.FromArgb(0, 255, 255, 255), LinearGradientMode.Vertical)) { gp.FillRectangle(brush, this.CaptionArea); } } else { switch (this.BackgroundImageLayout) { case ImageLayout.None: { #region None int gradientX = Math.Min(this.BackgroundImage.Width, 300); int gradientY = Math.Min(this.BackgroundImage.Height, 100); gp.DrawImage(this.BackgroundImage, new Point()); Rectangle rightGradientReg = new Rectangle(this.BackgroundImage.Width - gradientX, 0, gradientX, this.BackgroundImage.Height); Rectangle bottomGradientReg = new Rectangle(0, this.BackgroundImage.Height - gradientY, this.BackgroundImage.Width, gradientY); using (LinearGradientBrush hbrush = new LinearGradientBrush(rightGradientReg, Color.FromArgb(0, this.BackColor), Color.FromArgb(255, this.BackColor), 0F)) { rightGradientReg.X += 1; gp.FillRectangle(hbrush, rightGradientReg); } using (LinearGradientBrush vbrush = new LinearGradientBrush(bottomGradientReg, Color.FromArgb(0, this.BackColor), Color.FromArgb(255, this.BackColor), 90F)) { gp.FillRectangle(vbrush, bottomGradientReg); } #endregion } break; case ImageLayout.Stretch: { #region Stretch int gradientX = Math.Min(this.Width, 300); int gradientY = Math.Min(this.Height, 100); gp.DrawImage(this.BackgroundImage, new Rectangle(Point.Empty, this.Size), new Rectangle(0, 0, Math.Min(this.BackgroundImage.Width, this.Width), Math.Min(this.BackgroundImage.Height, this.Height)), GraphicsUnit.Pixel); Rectangle rightGradientReg = new Rectangle(this.Width - gradientX, 0, gradientX, this.Height); Rectangle bottomGradientReg = new Rectangle(0, this.Height - gradientY, this.Width, gradientY); Color rightside = BitmapDraw.GetBitmapEdgeColor(this.BackgroundImage, BorderSide.Right); Color bottomside = BitmapDraw.GetBitmapEdgeColor(this.BackgroundImage, BorderSide.Bottom); using (LinearGradientBrush hbrush = new LinearGradientBrush(rightGradientReg, Color.FromArgb(0, rightside), Color.FromArgb(255, rightside), 0F)) { rightGradientReg.X += 1; gp.FillRectangle(hbrush, rightGradientReg); } using (LinearGradientBrush vbrush = new LinearGradientBrush(bottomGradientReg, Color.FromArgb(0, bottomside), Color.FromArgb(255, bottomside), 90F)) { gp.FillRectangle(vbrush, bottomGradientReg); } #endregion } break; case ImageLayout.Tile: { #region Tile gp.DrawImage(this.BackgroundImage, new Rectangle(Point.Empty, this.Size), new Rectangle(Point.Empty, this.BackgroundImage.Size), GraphicsUnit.Pixel); #endregion } break; case ImageLayout.Center: { #region Center Rectangle targetRect = new Rectangle(Point.Empty, this.Size); Rectangle desRect = new Rectangle(Point.Empty, this.BackgroundImage.Size); if (this.Width > this.BackgroundImage.Width) { targetRect.X = (this.Width - this.BackgroundImage.Width) / 2; targetRect.Width = this.BackgroundImage.Width; } else if (this.Width < this.BackgroundImage.Width) { desRect.X = (this.BackgroundImage.Width - this.Width) / 2; desRect.Width = this.Width; } if (this.Height > this.BackgroundImage.Height) { targetRect.Y = (this.Height - this.BackgroundImage.Height) / 2; targetRect.Height = this.BackgroundImage.Height; } else if (this.Height < this.BackgroundImage.Height) { desRect.Y = (this.BackgroundImage.Height - this.Height) / 2; desRect.Height = this.Height; } gp.DrawImage(this.BackgroundImage, targetRect, desRect, GraphicsUnit.Pixel); int gradientW = Math.Min(this.BackgroundImage.Width, 300); int gradientH = Math.Min(this.BackgroundImage.Height, 100); Rectangle leftGradientReg = new Rectangle(targetRect.X - 1, targetRect.Y, gradientW, targetRect.Height); Rectangle topGradientReg = new Rectangle(targetRect.X, targetRect.Y, targetRect.Width, gradientH); Rectangle rightGradientReg = new Rectangle(targetRect.Width - gradientW + targetRect.X, targetRect.Y, gradientW, targetRect.Height); Rectangle bottomGradientReg = new Rectangle(targetRect.X, targetRect.Height - gradientH + targetRect.Y, targetRect.Width, gradientH); using (LinearGradientBrush lhbrush = new LinearGradientBrush(leftGradientReg, Color.FromArgb(255, this.BackColor), Color.FromArgb(0, this.BackColor), 0F)) { gp.FillRectangle(lhbrush, leftGradientReg); } using (LinearGradientBrush rhbrush = new LinearGradientBrush(rightGradientReg, Color.FromArgb(0, this.BackColor), Color.FromArgb(255, this.BackColor), 0F)) { rightGradientReg.X++; gp.FillRectangle(rhbrush, rightGradientReg); } using (LinearGradientBrush tvbrush = new LinearGradientBrush(topGradientReg, Color.FromArgb(255, this.BackColor), Color.FromArgb(0, this.BackColor), 90F)) { topGradientReg.Y--; gp.FillRectangle(tvbrush, topGradientReg); } using (LinearGradientBrush bvbrush = new LinearGradientBrush(bottomGradientReg, Color.FromArgb(0, this.BackColor), Color.FromArgb(255, this.BackColor), 90F)) { gp.FillRectangle(bvbrush, bottomGradientReg); } #endregion } break; case ImageLayout.Zoom: { #region Zoom gp.DrawImage(this.BackgroundImage, Point.Empty); Rectangle winRound = new Rectangle(Point.Empty, this.Size); using (LinearGradientBrush brush = new LinearGradientBrush(winRound, Color.FromArgb(60, this.BackColor), Color.FromArgb(200, this.BackColor), LinearGradientMode.Vertical)) { gp.FillRectangle(brush, winRound); } #endregion } break; default: { gp.DrawImage(this.BackgroundImage, new Rectangle(0, 0, this.Size.Width, this.Size.Height), new Rectangle(0, 0, this.BackgroundImage.Width, this.BackgroundImage.Height), GraphicsUnit.Pixel); } break; } } //绘制设计器时标题栏分界线 if (this.DesignMode && this.CaptionHeight > 0) { using (Pen pen = new Pen(Color.FromArgb(127, 0, 127))) gp.DrawLine(pen, 0, this.CaptionHeight - 1, this.Width - 1, this.CaptionHeight - 1); } //绘制边框 if (this.BorderWidth > 0) { using (Pen pen = new Pen(Color.FromArgb(50, Color.Black), this.BorderWidth)) { Rectangle outborderline = Rectangle.FromLTRB(0, 0, this.Size.Width - 1, this.Size.Height - 1); gp.DrawPath(pen, VectorDraw.CreateRoundRect(outborderline, this.CircularBeadRadius, BorderSide.None)); } } if (this.BorderLightWidth > 0) { using (Pen pen = new Pen(Color.FromArgb(50, Color.White), this.BorderLightWidth)) { Rectangle inborderline = Rectangle.FromLTRB(this.BorderWidth, this.BorderWidth, this.Size.Width - this.BorderWidth * 2, this.Size.Height - this.BorderWidth * 2); gp.DrawPath(pen, VectorDraw.CreateRoundRect(inborderline, this.CircularBeadRadius, BorderSide.None)); } } if (this.NCPaint != null) this.NCPaint.Invoke(new PaintEventArgs(gp, this.ClipNcRectangle)); } return img; }
重绘非客户区,大家可能注意到上面的代码
case WindowsMessages.WM_NCUAHDRAWCAPTION: return; case WindowsMessages.WM_NCUAHDRAWFRAME: return;
此处消息什么也不处理,也许是历史年代原因,上述消息是响应win98的机制,窗体非客户区的重绘会导致头部出现黑色块,我们将之屏蔽即可。
PS:当时的我可在这坑了很长时间。
大家都知道,其实winform最大的瓶颈就是性能!
但是导致重绘的原因很多,如,鼠标移动,窗体移动,大小改变等以及还有我们的主观控制。
所以我们应当尽可能的减少重绘次,以及增加局部重绘的条件。
头次写博客,没什么语言组织表达力,这篇博文会慢慢更新,请大家关注!
欢迎加入我的QQ群:56465289(C#技术交流群)