Winfrom中From控件的重绘

重绘目的

  • 1. 满足非默认主题下的标题栏样式
  • 2. 在保留停靠功能的同时进行重绘。

代码如下:

  1 public partial class FormEx: Form
  2     {
  3         public FormEx()
  4         {
  5             InitializeComponent();
  6             TitleBar.GetType().GetProperty("DoubleBuffered", BindingFlags.Instance | BindingFlags.NonPublic).SetValue(TitleBar, true, null);
  7             Icon = Properties.Resources.shark;
  8             CloseButtonImage = Properties.Resources.close;
  9             MaximumButtonImage = Properties.Resources.window_max;
 10             MaximumNormalButtonImage = Properties.Resources.window;
 11             MinimumButtonImage = Properties.Resources.window_min;
 12             CaptionBackgroundColor = Color.FromArgb(230, 230, 230);
 13             CaptionHeight = 30;
 14             BackColor = Color.White;
 15             ControlBackColor = Color.Transparent;
 16             this.TransparencyKey = boderColor;
 17             ControlActivedColor = DrawHelper.GetNearColor(Color.White, 0, -35, -24, -30);
 18 
 19             TitleBar.SendToBack();
 20 
 21             base.SetStyle(
 22              ControlStyles.UserPaint |
 23              ControlStyles.AllPaintingInWmPaint |
 24              ControlStyles.OptimizedDoubleBuffer |
 25              ControlStyles.ResizeRedraw |
 26              ControlStyles.SupportsTransparentBackColor|
 27              ControlStyles.DoubleBuffer, true);
 28             base.AutoScaleMode = AutoScaleMode.None;
 29         }
 30 
 31         #region 公开变量
 32         [Category("标题栏"), Description("关闭按钮图片")]
 33         public Image CloseButtonImage { get; set; }
 34 
 35         [Category("标题栏"), Description("最大化按钮图片")]
 36         public Image MaximumButtonImage { get; set; }
 37 
 38         [Category("标题栏"), Description("最大化默认按钮图片")]
 39         public Image MaximumNormalButtonImage { get; set; }
 40 
 41         [Category("标题栏"), Description("最小化按钮图片")]
 42         public Image MinimumButtonImage { get; set; }
 43 
 44         [Category("标题栏"), Description("标题栏按钮鼠标悬浮背景色"), DefaultValue(typeof(Color), "#000000")]
 45         public Color ControlActivedColor { get; set; }
 46 
 47         [Category("标题栏"), Description("标题栏按钮默认状态背景色"), DefaultValue(typeof(Color))]
 48         public Color ControlBackColor { get; set; }
 49 
 50         private int captionHeight;
 51         [Category("标题栏"), Description("标题栏高度"), DefaultValue(typeof(int), "30")]
 52         public int CaptionHeight { get { return captionHeight; } set { captionHeight = value; TitleBar.Height = value; } }
 53 
 54         [Category("标题栏"), Description("标题位置")]
 55         public ContentAlignment TitleAlign { set; get; } = ContentAlignment.MiddleLeft;
 56 
 57         private Color captionBackgroundColor;
 58         [Category("标题栏"), Description("标题栏背景颜色"), DefaultValue(typeof(Color), "White")]
 59         public Color CaptionBackgroundColor
 60         {
 61             get { return captionBackgroundColor; }
 62             set
 63             {
 64                 captionBackgroundColor = value;
 65                 TitleBar.BackColor = captionBackgroundColor;
 66             }
 67         }
 68         #endregion
 69 
 70         #region 私有变量
 71 
 72         private MouseState _mouseState = MouseState.Out; 
 73         private Rectangle closeRect = Rectangle.Empty;      //关闭按钮范围
 74         private Rectangle maxRect = Rectangle.Empty;        //最大化按钮范围
 75         private Rectangle minRect = Rectangle.Empty;        //最小化按钮范围
 76         private Rectangle captionRect;                      //标题范围
 77 
 78         private int btnH = 24;              //按钮大小
 79         private int boderWidth = 8;         //边框宽度
 80         private Color boderColor = Color.FromArgb(254, 254, 253);
 81         #endregion
 82 
 83         #region 重绘事件
 84         private void TitleBar_Paint(object sender, PaintEventArgs e)
 85         {
 86             captionRect = new Rectangle(0, 0, TitleBar.Width, TitleBar.Height);
 87             DrawTitle(e.Graphics);
 88             DrawControlButton(e.Graphics);
 89         }
 90 
 91         protected override void OnPaint(PaintEventArgs e)
 92         {
 93             base.OnPaint(e);
 94             DrawBound(e.Graphics);
 95         }
 96 
 97         /// <summary>
 98         /// 绘制边框
 99         /// </summary>
100         private void DrawBound(Graphics g)
101         {
102             Pen pen = new Pen(boderColor, boderWidth * 2);
103             Rectangle rectangle = new Rectangle(0, 0, Width, Height);
104             g.DrawRectangle(pen, rectangle);
105             pen = new Pen(Color.Black, 1);
106             rectangle = new Rectangle(boderWidth - 1, boderWidth - 1, Width - boderWidth * 2 + 1, Height - boderWidth * 2 + 1);
107             g.DrawRectangle(pen, rectangle);
108             Padding = new Padding(boderWidth);
109         }
110 
111         /// <summary>
112         /// 绘制控制按钮
113         /// </summary>
114         private void DrawControlButton(Graphics g)
115         {
116             int x = ClientSize.Width - btnH - 15 - boderWidth;
117             if (CloseButtonImage != null)
118             {
119                 DrawButtonImage(ref closeRect, ref x, _mouseState == MouseState.CloseHover, g, CloseButtonImage);
120             }
121             if (MaximizeBox)
122             {
123                 if (WindowState == FormWindowState.Maximized && MaximumNormalButtonImage != null)
124                     DrawButtonImage(ref maxRect, ref x, _mouseState == MouseState.MaxHover, g, MaximumNormalButtonImage);
125                 else if (MaximizeBox && WindowState != FormWindowState.Maximized && MaximumButtonImage != null)
126                     DrawButtonImage(ref maxRect, ref x, _mouseState == MouseState.MaxHover, g, MaximumButtonImage);
127             }
128             if (MinimizeBox && MinimumButtonImage != null)
129             {
130                 DrawButtonImage(ref minRect, ref x, _mouseState == MouseState.MinHover, g, MinimumButtonImage);
131             }
132         }
133 
134         private void DrawButtonImage(ref Rectangle rect, ref int x, bool isHover, Graphics g, Image image)
135         {
136             //rect = new Rectangle(x, (captionHeight - btnH) / 2, btnH, btnH);
137             rect = new Rectangle(x, 0, btnH, btnH);
138             Brush brush = new SolidBrush(isHover ? ControlActivedColor : ControlBackColor);
139             g.FillRectangle(brush, rect);
140             g.DrawImage(image, rect);
141             if (image == CloseButtonImage)
142                 rect = new Rectangle(x, 0, btnH + boderWidth, btnH);
143             x -= btnH;
144         }
145 
146         /// <summary>
147         /// 绘制标题
148         /// </summary>
149         private void DrawTitle(Graphics g)
150         {
151             int x = 6;
152             if (ShowIcon && Icon != null)
153             {
154                 g.SmoothingMode = SmoothingMode.AntiAlias;
155                 ImageAttributes image = new ImageAttributes();
156                 image.SetWrapMode(WrapMode.TileFlipXY);
157                 using (Bitmap bitmap = Icon.ToBitmap())
158                 {
159                     Rectangle rec = new Rectangle(x, (captionHeight - btnH) / 2, CaptionHeight - 6, CaptionHeight - 6);
160                     g.DrawImage(bitmap, rec, 0, 0, bitmap.Width, bitmap.Height, GraphicsUnit.Pixel, image);
161                 }
162                 x += 35;
163             }
164             if (!string.IsNullOrEmpty(Text))
165             {
166                 int fontHeight = Size.Ceiling(g.MeasureString("Text", TitleBar.Font)).Height;
167                 int fontWidth = Size.Ceiling(g.MeasureString(Text, TitleBar.Font)).Width;
168                 Brush brush = new SolidBrush(ForeColor);
169                 if (TitleAlign == ContentAlignment.MiddleLeft)
170                     g.DrawString(Text, TitleBar.Font, brush, x, (CaptionHeight - fontHeight) / 2);
171                 else if (TitleAlign == ContentAlignment.TopCenter)
172                     g.DrawString(Text, TitleBar.Font, brush, (Width - fontWidth)/2, boderWidth);
173 
174 
175             }
176         }
177         #endregion
178 
179         #region 其他事件
180         private void TitleBar_MouseClick(object sender, MouseEventArgs e)
181         {
182             if (e.Clicks != 1 || e.Button != MouseButtons.Left)
183                 return;
184             switch (_mouseState)
185             {
186                 case MouseState.CloseHover:
187                     Close();
188                     break;
189                 case MouseState.MaxHover:
190                     WindowState = WindowState == FormWindowState.Maximized ? FormWindowState.Normal : FormWindowState.Maximized;
191                     return;
192                 case MouseState.MinHover:
193                     WindowState = FormWindowState.Minimized;
194                     return;
195             }
196             _mouseState = MouseState.Normal;
197         }
198 
199         private void TitleBar_MouseDown(object sender, MouseEventArgs e)
200         {
201             if (_mouseState != MouseState.CaptionHover)
202                 return;
203 
204             if (e.Clicks == 1)
205             {
206                 Win32API.ReleaseCapture();
207                 Win32API.SendMessage(Handle, Win32API.WM_SYSCOMMAND, Win32API.SC_MOVE + Win32API.HTCAPTION, 0);
208             }
209             else if (e.Clicks == 2 && e.Button == MouseButtons.Left)
210             {
211                 WindowState = WindowState == FormWindowState.Maximized ? FormWindowState.Normal : FormWindowState.Maximized;
212             }
213         }
214 
215         private void TitleBar_MouseMove(object sender, MouseEventArgs e)
216         {
217             Point p = new Point(e.X, e.Y);
218             if (closeRect != Rectangle.Empty && closeRect.Contains(p))
219                 _mouseState = MouseState.CloseHover;
220             else if (minRect != Rectangle.Empty && minRect.Contains(p))
221                 _mouseState = MouseState.MinHover;
222             else if (maxRect != Rectangle.Empty && maxRect.Contains(p))
223                 _mouseState = MouseState.MaxHover;
224             else if (captionRect != Rectangle.Empty && captionRect.Contains(p))
225                 _mouseState = MouseState.CaptionHover;
226             else
227                 _mouseState = MouseState.Normal;
228             
229             Invalidate(captionRect, true);
230         }
231 
232         private void TitleBar_MouseLeave(object sender, EventArgs e)
233         {
234             _mouseState = MouseState.Out;
235             Invalidate(captionRect, true);
236         }
237 
238         private void FormEx_SizeChanged(object sender, EventArgs e)
239         {
240             Invalidate(captionRect, true);
241         }
242         #endregion
243 
244         #region 调整窗口大小
245 
246         protected override void SetBoundsCore(int x, int y, int width, int height, BoundsSpecified specified)
247         {
248             if (width == Width + 16)
249                 return;
250             base.SetBoundsCore(x, y, width, height, specified);
251         }
252 
253         protected override void WndProc(ref Message m)
254         {
255             if (_mouseState == MouseState.CloseHover || _mouseState == MouseState.MinHover)
256             {
257                 base.WndProc(ref m);
258                 return;
259             }
260             switch (m.Msg)
261             {
262                 case 0x0084:
263                     base.WndProc(ref m);
264                     Point vPoint = new Point((int)m.LParam & 0xFFFF,
265                         (int)m.LParam >> 16 & 0xFFFF);
266                     vPoint = PointToClient(vPoint);
267                     if (vPoint.X <= 10)
268                         if (vPoint.Y <= 10)
269                             m.Result = (IntPtr)Win32API.Guying_HTTOPLEFT;
270                         else if (vPoint.Y >= ClientSize.Height - 10)
271                             m.Result = (IntPtr)Win32API.Guying_HTBOTTOMLEFT;
272                         else m.Result = (IntPtr)Win32API.Guying_HTLEFT;
273                     else if (vPoint.X >= ClientSize.Width - 10)
274                         if (vPoint.Y <= 10)
275                             m.Result = (IntPtr)Win32API.Guying_HTTOPRIGHT;
276                         else if (vPoint.Y >= ClientSize.Height - 10)
277                             m.Result = (IntPtr)Win32API.Guying_HTBOTTOMRIGHT;
278                         else m.Result = (IntPtr)Win32API.Guying_HTRIGHT;
279                     else if (vPoint.Y <= 10)
280                         m.Result = (IntPtr)Win32API.Guying_HTTOP;
281                     else if (vPoint.Y >= ClientSize.Height - 10)
282                         m.Result = (IntPtr)Win32API.Guying_HTBOTTOM;
283                     break;
284                 case 0x0201:                    //鼠标左键按下的消息   
285                     m.Msg = 0x00A1;             //更改消息为非客户区按下鼠标   
286                     m.LParam = IntPtr.Zero;     //默认值   
287                     m.WParam = new IntPtr(2);   //鼠标放在标题栏内   
288                     base.WndProc(ref m);
289                     break;
290                 case 0x0083:
291                     if (m.WParam != IntPtr.Zero)
292                     {
293                         NCCALCSIZE_PARAMS rcsize = (NCCALCSIZE_PARAMS)Marshal.PtrToStructure(m.LParam, typeof(NCCALCSIZE_PARAMS));
294                         Marshal.StructureToPtr(rcsize, m.LParam, false);
295                     }
296                     m.Result = new IntPtr(1);
297                     break;
298                 default:
299                     base.WndProc(ref m);
300                     break;
301             }
302         }
303         #endregion
304     }
305 
306     public enum MouseState
307     {
308         Normal,
309         MaxHover,
310         MinHover,
311         CloseHover,
312         CaptionHover,
313         Out,
314     }

因为主要目的是为了保留窗体是停靠功能,所以不能使用无边框然后直接重绘标题栏。拦截了window绘制有效区域标题栏的消息,仍然存在很多不完善的地方,如拦截边框消息后没有重新绘制原边框位置的图形,导致了原区域的透明等等。

posted @ 2019-09-25 09:53  柠檬山竹大西瓜  阅读(395)  评论(1编辑  收藏  举报