重绘目的

  • 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(, , );
  13. CaptionHeight = ;
  14. BackColor = Color.White;
  15. ControlBackColor = Color.Transparent;
  16. this.TransparencyKey = boderColor;
  17. ControlActivedColor = DrawHelper.GetNearColor(Color.White, , -, -, -);
  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), "")]
  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 = ; //按钮大小
  79. private int boderWidth = ; //边框宽度
  80. private Color boderColor = Color.FromArgb(, , );
  81. #endregion
  82.  
  83. #region 重绘事件
  84. private void TitleBar_Paint(object sender, PaintEventArgs e)
  85. {
  86. captionRect = new Rectangle(, , 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 * );
  103. Rectangle rectangle = new Rectangle(, , Width, Height);
  104. g.DrawRectangle(pen, rectangle);
  105. pen = new Pen(Color.Black, );
  106. rectangle = new Rectangle(boderWidth - , boderWidth - , Width - boderWidth * + , Height - boderWidth * + );
  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 - - 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, , 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, , btnH + boderWidth, btnH);
  143. x -= btnH;
  144. }
  145.  
  146. /// <summary>
  147. /// 绘制标题
  148. /// </summary>
  149. private void DrawTitle(Graphics g)
  150. {
  151. int x = ;
  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) / , CaptionHeight - , CaptionHeight - );
  160. g.DrawImage(bitmap, rec, , , bitmap.Width, bitmap.Height, GraphicsUnit.Pixel, image);
  161. }
  162. x += ;
  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) / );
  171. else if (TitleAlign == ContentAlignment.TopCenter)
  172. g.DrawString(Text, TitleBar.Font, brush, (Width - fontWidth)/, boderWidth);
  173.  
  174. }
  175. }
  176. #endregion
  177.  
  178. #region 其他事件
  179. private void TitleBar_MouseClick(object sender, MouseEventArgs e)
  180. {
  181. if (e.Clicks != || e.Button != MouseButtons.Left)
  182. return;
  183. switch (_mouseState)
  184. {
  185. case MouseState.CloseHover:
  186. Close();
  187. break;
  188. case MouseState.MaxHover:
  189. WindowState = WindowState == FormWindowState.Maximized ? FormWindowState.Normal : FormWindowState.Maximized;
  190. return;
  191. case MouseState.MinHover:
  192. WindowState = FormWindowState.Minimized;
  193. return;
  194. }
  195. _mouseState = MouseState.Normal;
  196. }
  197.  
  198. private void TitleBar_MouseDown(object sender, MouseEventArgs e)
  199. {
  200. if (_mouseState != MouseState.CaptionHover)
  201. return;
  202.  
  203. if (e.Clicks == )
  204. {
  205. Win32API.ReleaseCapture();
  206. Win32API.SendMessage(Handle, Win32API.WM_SYSCOMMAND, Win32API.SC_MOVE + Win32API.HTCAPTION, );
  207. }
  208. else if (e.Clicks == && e.Button == MouseButtons.Left)
  209. {
  210. WindowState = WindowState == FormWindowState.Maximized ? FormWindowState.Normal : FormWindowState.Maximized;
  211. }
  212. }
  213.  
  214. private void TitleBar_MouseMove(object sender, MouseEventArgs e)
  215. {
  216. Point p = new Point(e.X, e.Y);
  217. if (closeRect != Rectangle.Empty && closeRect.Contains(p))
  218. _mouseState = MouseState.CloseHover;
  219. else if (minRect != Rectangle.Empty && minRect.Contains(p))
  220. _mouseState = MouseState.MinHover;
  221. else if (maxRect != Rectangle.Empty && maxRect.Contains(p))
  222. _mouseState = MouseState.MaxHover;
  223. else if (captionRect != Rectangle.Empty && captionRect.Contains(p))
  224. _mouseState = MouseState.CaptionHover;
  225. else
  226. _mouseState = MouseState.Normal;
  227.  
  228. Invalidate(captionRect, true);
  229. }
  230.  
  231. private void TitleBar_MouseLeave(object sender, EventArgs e)
  232. {
  233. _mouseState = MouseState.Out;
  234. Invalidate(captionRect, true);
  235. }
  236.  
  237. private void FormEx_SizeChanged(object sender, EventArgs e)
  238. {
  239. Invalidate(captionRect, true);
  240. }
  241. #endregion
  242.  
  243. #region 调整窗口大小
  244.  
  245. protected override void SetBoundsCore(int x, int y, int width, int height, BoundsSpecified specified)
  246. {
  247. if (width == Width + )
  248. return;
  249. base.SetBoundsCore(x, y, width, height, specified);
  250. }
  251.  
  252. protected override void WndProc(ref Message m)
  253. {
  254. if (_mouseState == MouseState.CloseHover || _mouseState == MouseState.MinHover)
  255. {
  256. base.WndProc(ref m);
  257. return;
  258. }
  259. switch (m.Msg)
  260. {
  261. case 0x0084:
  262. base.WndProc(ref m);
  263. Point vPoint = new Point((int)m.LParam & 0xFFFF,
  264. (int)m.LParam >> & 0xFFFF);
  265. vPoint = PointToClient(vPoint);
  266. if (vPoint.X <= )
  267. if (vPoint.Y <= )
  268. m.Result = (IntPtr)Win32API.Guying_HTTOPLEFT;
  269. else if (vPoint.Y >= ClientSize.Height - )
  270. m.Result = (IntPtr)Win32API.Guying_HTBOTTOMLEFT;
  271. else m.Result = (IntPtr)Win32API.Guying_HTLEFT;
  272. else if (vPoint.X >= ClientSize.Width - )
  273. if (vPoint.Y <= )
  274. m.Result = (IntPtr)Win32API.Guying_HTTOPRIGHT;
  275. else if (vPoint.Y >= ClientSize.Height - )
  276. m.Result = (IntPtr)Win32API.Guying_HTBOTTOMRIGHT;
  277. else m.Result = (IntPtr)Win32API.Guying_HTRIGHT;
  278. else if (vPoint.Y <= )
  279. m.Result = (IntPtr)Win32API.Guying_HTTOP;
  280. else if (vPoint.Y >= ClientSize.Height - )
  281. m.Result = (IntPtr)Win32API.Guying_HTBOTTOM;
  282. break;
  283. case 0x0201: //鼠标左键按下的消息
  284. m.Msg = 0x00A1; //更改消息为非客户区按下鼠标
  285. m.LParam = IntPtr.Zero; //默认值
  286. m.WParam = new IntPtr(); //鼠标放在标题栏内
  287. base.WndProc(ref m);
  288. break;
  289. case 0x0083:
  290. if (m.WParam != IntPtr.Zero)
  291. {
  292. NCCALCSIZE_PARAMS rcsize = (NCCALCSIZE_PARAMS)Marshal.PtrToStructure(m.LParam, typeof(NCCALCSIZE_PARAMS));
  293. Marshal.StructureToPtr(rcsize, m.LParam, false);
  294. }
  295. m.Result = new IntPtr();
  296. break;
  297. default:
  298. base.WndProc(ref m);
  299. break;
  300. }
  301. }
  302. #endregion
  303. }
  304.  
  305. public enum MouseState
  306. {
  307. Normal,
  308. MaxHover,
  309. MinHover,
  310. CloseHover,
  311. CaptionHover,
  312. Out,
  313. }

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

Winfrom中From控件的重绘的更多相关文章

  1. 玩转控件:重绘DEVEXPRESS中DateEdit控件 —— 让DateEdit支持只选择年月 (提供源码下载)

      前言 上一篇博文<玩转控件:重绘ComboBox —— 让ComboBox多列显示>中,根据大家的回馈,ComboBox已经支持筛选了,更新见博文最后最后最后面.   奇葩 这两天遇到 ...

  2. 玩转控件:重写/重绘Dev中MessageBox弹窗控件

    很久没有更新博客了,本想着直接发一篇<手撕ERP>系列,从控件重写.重绘,到框架搭建,再到部分模块实现+业务的.但是每次动手的时候,都觉得难以下手.直接从数据库设计开始吧,模块设计还没定下 ...

  3. winfrom中pictureBox控件的部分使用方法

    一.后台属性 1.pictureBox1.Image显示图片 2.pictureBox1.ImageLocation存储和提取图片路径 二.面板属性 1.Picturebox控件SizeMode属性 ...

  4. VC++中关于控件重绘函数/消息 OnPaint,OnDraw,OnDrawItem,DrawItem的区别

    而OnPaint()是CWnd的类成员,同时负责响应WM_PAINT消息. OnDraw()是CVIEW的成员函数,并且没有响应消息的功能.这就是为什么你用VC成的程序代码时,在视图类只有OnDraw ...

  5. ArcGIS Engine开发之旅03--ArcGIS Engine中的控件

    原文:ArcGIS Engine开发之旅03--ArcGIS Engine中的控件 制图控件,如MapControl.PageLayoutControl,其中MapControl控件主要用于地理数据的 ...

  6. 玩转控件:对Dev中GridControl控件的封装和扩展

    又是一年清明节至,细雨绵绵犹如泪光,树叶随风摆动.... 转眼间,一年又过去了三分之一,疫情的严峻让不少企业就跟清明时节的树叶一样,摇摇欲坠.裁员的裁员,降薪的降薪,996的996~~说起来都是泪,以 ...

  7. CSharpGL(26)在opengl中实现控件布局/渲染文字

    CSharpGL(26)在opengl中实现控件布局/渲染文字 效果图 如图所示,可以将文字.坐标轴固定在窗口的一角. 下载 CSharpGL已在GitHub开源,欢迎对OpenGL有兴趣的同学加入( ...

  8. WPF中Ribbon控件的使用

    这篇博客将分享如何在WPF程序中使用Ribbon控件.Ribbon可以很大的提高软件的便捷性. 上面截图使Outlook 2010的界面,在Home标签页中,将所属的Menu都平铺的布局,非常容易的可 ...

  9. Android线程中设置控件

    在Android中经常出现多线程中设置控件的值报错的情况,今天教大家封装一个简单的类避免这样的问题,同样也调用实现也非常的方便. 自定义类: /** * Created by wade on 2016 ...

随机推荐

  1. potel99se 文件损坏修复

    一直使用protel99se来做电路图,非常方便快捷.最近一次打开常用的一个ddb文件,提示失败,无法打开了.protel99使用的数据库文件实际上是access97 的mdb数据库,于是修改成mdb ...

  2. Linux 常用工具openssh之ssh-add

    前言 ssh-add命令是把专用密钥添加到ssh-agent的高速缓存中,从而提高ssh的认证速度 语法 ssh-add [-cDdLlXx] [-t life] [file ...] 选项 -D:删 ...

  3. QIIME2使用方法

    激活qiime2的执行环境:source activate qiime2-2019.4如何查看conda已有的环境:conda info -e 以下分析流程参考:https://docs.qiime2 ...

  4. Ceph 存储集群7-故障排除

    Ceph 仍在积极开发中,所以你可能碰到一些问题,需要评估 Ceph 配置文件.并修改日志和调试选项来纠正它. 一.日志记录和调试 般来说,你应该在运行时增加调试选项来调试问题:也可以把调试选项添加到 ...

  5. 安卓开发实战-记账本APP(五)

    今天将昨天剩余的bug修复,并且完成图标的美化,设置长按删除,模仿支付宝实现金额的动态增加. ①将昨天的布局进行了修改:之前是fragment,改成FrameLayout布局,不再设置name,进而在 ...

  6. xgboost load model from demp text file

    python package : https://github.com/mwburke/xgboost-python-deploy import xgboost as xgb import numpy ...

  7. Redis 3.2.3: 集群3哨兵模式

    简介 Redis是一个使用ANSI C编写的开源.支持网络.基于内存.可选持久性的键值对存储数据库.从2015年6月开始,Redis的开发由Redis Labs赞助,而2013年5月至2015年6月期 ...

  8. .Net Core中IOC容器的使用

    打代码之前先说一下几个概念,那就是什么是IOC.DI.DIP 虽然网上讲这些的已经有很多了,我这里还是要再赘述一下 IOC容器就是一个工厂,负责创建对象的 IOC控制反转:只是把上端对下端的依赖,换成 ...

  9. Go语言实现:【剑指offer】调整数组顺序使奇数位于偶数前面

    该题目来源于牛客网<剑指offer>专题. 输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,所有的偶数位于数组的后半部分,并保证奇数和奇数,偶数和 ...

  10. Centos7.6安装zabbix留纪录

    1)查看系统版本 [root@zabbix-s41 ~]# cat /etc/redhat-release CentOS Linux release (Core) [root@zabbix-s41 ~ ...