在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
重绘窗体的工作区的时候我们可以用到OnPaint来实现。而非工作区的绘制有几种思路 1.直接实现WM_NCCALCSIZE消息绘制 2.把窗体修改成None状态并拦截WM_NCCALCSIZE修改非工作区的大小实现 3.把窗体修改成None直接做一个模拟的状态 这三种方法都会有一些弱点,这些弱点也许是我没有找到对应的解决方法 。 1.在实现后需要修改 base.ControlBox = false,要不然在鼠标经过的时候会出现如下图的效果 其实我们是要的下面的这种效果 但是这样做的后果是无法使用任务栏的菜单 ,如果有谁知道这个怎么解决的话留个言,在此谢过了
2.第二种实现的话在最大化最小化的时候,不知道是什么原因会产生窗体自动缩小在WM_NCCALCSIZE定义的标题栏的大小,这个也有一个折中的解决方法,就是重写SetBoundsCore然后注释掉里面的内容,但是在这样的话在Visual Studio里面就无法改变窗体的大小了。 如果这个也有解决方法的话,在此谢过了。 protected override void SetBoundsCore(int x, int y, int width, int height, BoundsSpecified specified) { //base.SetBoundsCore(x, y, width, height, specified); } 3.第三种当然是最好实现的了 ,但是模拟的状态无法直接替换到以前已经写好的窗体,直接否掉了 。
第一种和第二种其实是有点类似的,主要的地方还是在绘制上面 。
重绘非工作区,这个地方的重点在 DarwRegion函数里的 using (Bitmap img = new Bitmap(this.Bounds.Width, this.Bounds.Height)) { Graphics g = Graphics.FromImage(img); …… gs.DrawImage(img, Point.Empty); } 这里利用双缓存先在图片上绘制了然后在画在窗体上
/// <summary> /// 重绘非工作区 /// </summary> private void NCPaint() { IntPtr wdc = Common.GetWindowDC(this.Handle);// Graphics.FromHwnd(this.Handle); Graphics g = Graphics.FromHdc(wdc); try { DarwRegion(g); } catch { } Common.ReleaseDC(this.Handle, wdc); } private void DarwRegion(Graphics gs) { if (this.FormBorderStyle == FormBorderStyle.None) return; using (Bitmap img = new Bitmap(this.Bounds.Width, this.Bounds.Height)) { Graphics g = Graphics.FromImage(img); if (mouseMove == MouseMose.None) { GraphicsPath drawRect = RectX(new Rectangle(0, 0, this.Bounds.Width, this.Bounds.Height), Arc); //绘制渐变色 Rectangle rect = new Rectangle(0, 0, this.Bounds.Width, this.Bounds.Height); LinearGradientBrush brush = new LinearGradientBrush(rect, this._colorA, this._colorB, 90); drawRect.AddRectangle(new Rectangle(BorderWidth, HeadHeight, this.ClientSize.Width, this.ClientSize.Height)); g.FillPath(brush, drawRect); //绘制图标Icon if (ShowIcon) g.DrawIcon(this.Icon, new Rectangle(BorderWidth + 5, (HeadHeight - 16) / 2, 16, 16)); //绘制标题 StringFormat sf = new StringFormat(); sf.LineAlignment = StringAlignment.Center; //求标题栏的区域 ToolTitle = new Rectangle(BorderWidth + 23, 0, this.Bounds.Width, HeadHeight); g.DrawString(this.Text, this.Font, new SolidBrush(this.ForeColor), ToolTitle, sf); //绘制最大最小关闭按钮 //g.DrawImage(butClose, ButClose); //g.DrawImage(butMax, ButMax); //g.DrawImage(butMin, ButMin); DrawButton(g); //绘制边框 g.SmoothingMode = SmoothingMode.HighQuality; //高质量 drawRect = RectX(new Rectangle(1, 1, this.Bounds.Width - 4, this.Bounds.Height - 4), Arc - 1); g.DrawPath(new Pen(Color.FromArgb(100, Color.White), 1), drawRect);//绘制内边框 drawRect = RectX(new Rectangle(0, 0, this.Bounds.Width - 2, this.Bounds.Height - 2), Arc - 1); g.DrawPath(new Pen(SolidColor, 1), drawRect);//绘制外边框 } else { int i = this.Bounds.Width - 3, h = 1; foreach (ToolButton a in ListButton) { if (!a.Start) continue; i = i - a.Size.Width; Rectangle rect = new Rectangle(new Point(i, h), a.Size); if (a == _newbutton) { g.FillRectangle(new SolidBrush(ColorA), rect); g.DrawImage(a.Move, rect); } else if (a == _oldbutton) { g.FillRectangle(new SolidBrush(ColorA), rect); g.DrawImage(a.Default, rect); } } } gs.DrawImage(img, Point.Empty); } }
最后是几个需要重绘的消息 /// <summary> /// 非客户区刷新 /// </summary> private void NCUpdate() { Common.SendMessage(this.Handle, (int)Msg.WM_NCPAINT, 0, 0); } switch (m.Msg) { case (int)Msg.WM_NCCALCSIZE: BorderWidth = (this.Bounds.Width - this.ClientSize.Width) / 2; HeadHeight = this.Bounds.Height - this.ClientSize.Height - BorderWidth; mouseMove = MouseMose.None; // NCPaint(); base.WndProc(ref m); break; case (int)Msg.WM_NCACTIVATE: base.WndProc(ref m); mouseMove = MouseMose.None; NCUpdate(); break; case (int)Msg.WM_NCPAINT: NCPaint(); break; case (int)Msg.WM_NCLBUTTONDOWN: if (GetMouseButton() == null) { base.WndProc(ref m); // Console.WriteLine(1); } break; case (int)Msg.WM_NCLBUTTONUP: ToolButton but = GetMouseButton(); if (but != null) { but.OnClick(); } base.WndProc(ref m); break; case (int)Msg.WM_NCMOUSEMOVE: NewButton = GetMouseButton(); base.WndProc(ref m); break; case (int)Msg.WM_ERASEBKGND: base.WndProc(ref m); NCPaint(); mouseMove = MouseMose.None; NCUpdate(); break; default: base.WndProc(ref m); break; } 在这里鼠标点击关闭按钮是会出现WM_NCLBUTTONDOWN无法接收到消息,研究了很久发现了一个可以收到的方法,在WM_NCLBUTTONUP事件中判断是否是在最大最小关闭按钮按下的,如果是就不执行base.WndProc(ref m)这句。 基本上窗体绘制的原理就这么些东西了,如果哪位同学对上面的方法有更好的建议的话,欢迎讨论 。 |
请发表评论