TreeViewEx.cs 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459
  1. using System.Drawing;
  2. using System.Runtime.InteropServices;
  3. using System.Reflection;
  4. using System.Drawing.Drawing2D;
  5. namespace System.Windows.Forms
  6. {
  7. public class TreeViewEx : TreeView
  8. {
  9. #region 双缓存重绘
  10. private const int WM_VSCROLL = 0x0115;
  11. private const int WM_HSCROLL = 0x0114;
  12. //private const int WM_MOUSEWHEEL = 0x020A;
  13. private const int TV_FIRST = 0x1100;
  14. private const int TVM_SETBKCOLOR = TV_FIRST + 29;
  15. private const int TVM_SETEXTENDEDSTYLE = TV_FIRST + 44;
  16. private const int TVS_EX_DOUBLEBUFFER = 0x0004;
  17. private void UpdateExtendedStyles()
  18. {
  19. typeof(Control).GetProperty("DoubleBuffered", BindingFlags.Instance | BindingFlags.NonPublic).SetValue(treeView1, true, null);
  20. }
  21. protected override void OnHandleCreated(EventArgs e)
  22. {
  23. base.OnHandleCreated(e);
  24. UpdateExtendedStyles();
  25. //if (!API.IsWinXP)
  26. // API.SendMessage(Handle, TVM_SETBKCOLOR, IntPtr.Zero, (IntPtr)ColorTranslator.ToWin32(BackColor));
  27. }
  28. protected override void OnPaint(PaintEventArgs e)
  29. {
  30. if (GetStyle(ControlStyles.UserPaint))
  31. {
  32. Message m = new Message();
  33. m.HWnd = Handle;
  34. m.Msg = API.WM_PRINTCLIENT;
  35. m.WParam = e.Graphics.GetHdc();
  36. m.LParam = (IntPtr)API.PRF_CLIENT;
  37. DefWndProc(ref m);
  38. e.Graphics.ReleaseHdc(m.WParam);
  39. }
  40. base.OnPaint(e);
  41. }
  42. #endregion
  43. public TreeViewEx()
  44. {
  45. treeView1 = this;
  46. treeView1.HotTracking = true;
  47. treeView1.HideSelection = false;
  48. //treeView1.SelectedImageIndex = treeView1.ImageIndex;
  49. this.treeView1.BackColor = System.Drawing.Color.White;
  50. this.treeView1.BorderStyle = System.Windows.Forms.BorderStyle.None;
  51. this.treeView1.Font = new System.Drawing.Font("微软雅黑", 9.7F);
  52. treeView1.DrawMode = TreeViewDrawMode.OwnerDrawAll;
  53. this.treeView1.FullRowSelect = true;
  54. this.treeView1.ShowLines = false;
  55. this.treeView1.DrawNode += new System.Windows.Forms.DrawTreeNodeEventHandler(this.treeView1_DrawNode);
  56. this.treeView1.BeforeSelect += new System.Windows.Forms.TreeViewCancelEventHandler(this.treeView1_BeforeSelect);
  57. //this.treeView1.KeyDown += new System.Windows.Forms.KeyEventHandler(this.treeView1_KeyDown);
  58. }
  59. #region DrawNode
  60. public ImageList arrowImageList
  61. {
  62. get
  63. {
  64. return arrowImageList1;
  65. }
  66. set
  67. {
  68. arrowImageList1 = value;
  69. }
  70. }
  71. public Color SelectColor
  72. {
  73. get
  74. {
  75. return m_SelectColor;
  76. }
  77. set
  78. {
  79. m_SelectColor = value;
  80. m_SelectColorBrush = new SolidBrush(Color.FromArgb(100, m_SelectColor.R, m_SelectColor.G, m_SelectColor.B));
  81. //Color ex = Color.FromArgb(100, m_SelectColor.R, m_SelectColor.G, m_SelectColor.B);
  82. //m_SelectColorBrushxx = new LinearGradientBrush(this.ClientRectangle,m_SelectColor,ex,LinearGradientMode.ForwardDiagonal);
  83. m_SelectPen = new Pen(m_SelectColor);
  84. }
  85. }
  86. public Color SelectColor2
  87. {
  88. get
  89. {
  90. return m_SelectColor2;
  91. }
  92. set
  93. {
  94. m_SelectColor2 = value;
  95. m_SelectColorBrush2 = new SolidBrush(Color.FromArgb(100, m_SelectColor2.R,m_SelectColor2.G, m_SelectColor2.B));
  96. //Color ex = Color.FromArgb(100, m_SelectColor2.R, m_SelectColor2.G, m_SelectColor2.B);
  97. //m_SelectColorBrushxx2 = new LinearGradientBrush(this.ClientRectangle, m_SelectColor2, ex, LinearGradientMode.ForwardDiagonal);
  98. m_SelectPen2 = new Pen(m_SelectColor2);
  99. }
  100. }
  101. public Color ColorEx
  102. {
  103. get
  104. {
  105. return m_Color;
  106. }
  107. set
  108. {
  109. m_Color = value;
  110. m_ColorBrush = new SolidBrush(Color.FromArgb(100,m_Color.R, m_Color.G, m_Color.B));
  111. //Color ex = Color.FromArgb(100, m_Color.R, m_Color.G, m_Color.B);
  112. //m_ColorBrushxx = new LinearGradientBrush(this.ClientRectangle, m_Color, ex, LinearGradientMode.ForwardDiagonal);
  113. m_Pen = new Pen(m_Color);
  114. }
  115. }
  116. private SolidBrush m_SelectColorBrush;
  117. //private Brush m_SelectColorBrushxx;
  118. private SolidBrush m_SelectColorBrush2;
  119. //private Brush m_SelectColorBrushxx2;
  120. private SolidBrush m_ColorBrush;
  121. //private Brush m_ColorBrushxx;
  122. private Pen m_SelectPen;
  123. private Pen m_SelectPen2;
  124. private Pen m_Pen;
  125. /*1节点被选中 ,TreeView有焦点*/
  126. private SolidBrush brush1 = new SolidBrush(Color.FromArgb(209, 232, 255));//填充颜色
  127. private Pen pen1 = new Pen(Color.FromArgb(102, 167, 232), 1);//边框颜色
  128. /*2节点被选中 ,TreeView没有焦点*/
  129. private SolidBrush brush2 = new SolidBrush(Color.FromArgb(247, 247, 247));
  130. private Pen pen2 = new Pen(SystemColors.ControlLight, 1);
  131. /*3 MouseMove的时候 画光标所在的节点的背景*/
  132. private SolidBrush brush3 = new SolidBrush(Color.AliceBlue); // 鼠标停止
  133. private Pen pen3 = new Pen(SystemColors.ControlLight, 1); // 选中
  134. private void treeView1_DrawNode(object sender, DrawTreeNodeEventArgs e)
  135. {
  136. try
  137. {
  138. //if (BackColorBrush == null)
  139. //{
  140. // BackColorBrush = new SolidBrush(treeView1.BackColor);
  141. //}
  142. SolidBrush BackColorBrush = new SolidBrush(treeView1.BackColor);
  143. Rectangle nodeRect = new Rectangle(2, e.Bounds.Top, e.Bounds.Width - 5, e.Bounds.Height-1);
  144. #region 1 选中的节点背景=========================================
  145. if (e.Node.IsSelected)
  146. {
  147. //TreeView有焦点的时候 画选中的节点
  148. //if (treeView1.Focused)
  149. if(e.State != (TreeNodeStates.Focused|TreeNodeStates.Selected))
  150. {
  151. if (m_SelectColor != null)
  152. {
  153. e.Graphics.FillRectangle(m_SelectColorBrush, nodeRect);
  154. //e.Graphics.DrawRectangle(m_SelectPen, nodeRect);
  155. }
  156. else
  157. {
  158. e.Graphics.FillRectangle(brush1, nodeRect);
  159. //e.Graphics.DrawRectangle(pen1, nodeRect);
  160. }
  161. /*测试 画聚焦的边框*/
  162. ControlPaint.DrawFocusRectangle(e.Graphics, nodeRect, Color.Black, SystemColors.Highlight);
  163. }
  164. /*TreeView失去焦点的时候 */
  165. else
  166. {
  167. if (m_SelectColor2 != null)
  168. {
  169. e.Graphics.FillRectangle(m_SelectColorBrush2, nodeRect);
  170. //e.Graphics.DrawRectangle(m_SelectPen2, nodeRect);
  171. }
  172. else
  173. {
  174. e.Graphics.FillRectangle(brush2, nodeRect);
  175. //e.Graphics.DrawRectangle(pen2, nodeRect);
  176. }
  177. }
  178. }
  179. else if ((e.State & TreeNodeStates.Hot) != 0 && e.Node.Text != "")//|| currentMouseMoveNode == e.Node)
  180. {
  181. if (ColorEx != null)
  182. {
  183. e.Graphics.FillRectangle(m_ColorBrush, nodeRect);
  184. e.Graphics.DrawRectangle(m_Pen, nodeRect);
  185. }
  186. else
  187. {
  188. e.Graphics.FillRectangle(brush3, nodeRect);
  189. e.Graphics.DrawRectangle(pen3, nodeRect);
  190. }
  191. }
  192. else
  193. {
  194. e.Graphics.FillRectangle(BackColorBrush, e.Bounds);
  195. }
  196. #endregion
  197. #region 2 +-号绘制=========================================
  198. Rectangle plusRect;
  199. if (treeView1.ImageList != null)
  200. {
  201. plusRect = new Rectangle(e.Node.Bounds.Left - 32, nodeRect.Top + 7, 9, 9); // +-号的大小 是9 * 9
  202. }
  203. else
  204. {
  205. plusRect = new Rectangle(e.Node.Bounds.Left - 20, nodeRect.Top + 7, 9, 9); // +-号的大小 是9 * 9
  206. }
  207. if (e.Node.IsExpanded)
  208. e.Graphics.DrawImage(arrowImageList.Images[1], plusRect);
  209. else if (e.Node.IsExpanded == false && e.Node.Nodes.Count > 0)
  210. e.Graphics.DrawImage(arrowImageList.Images[0], plusRect);
  211. #endregion
  212. #region 3 画节点文本=========================================
  213. Rectangle nodeTextRect = new Rectangle(e.Node.Bounds.Left, e.Node.Bounds.Top + 2, e.Node.Bounds.Width + 2, e.Node.Bounds.Height);
  214. nodeTextRect.Width += 4;
  215. nodeTextRect.Height -= 4;
  216. e.Graphics.DrawString(e.Node.Text, e.Node.TreeView.Font, new SolidBrush(Color.Black), nodeTextRect);
  217. ////画子节点个数 (111)
  218. //if (e.Node.GetNodeCount(true) > 0)
  219. //{
  220. // e.Graphics.DrawString(string.Format("({0})", e.Node.GetNodeCount(false)),
  221. // new Font("Arial", 8),
  222. // Brushes.Gray,
  223. // nodeTextRect.Right - 4,
  224. // nodeTextRect.Top + 2);
  225. //}
  226. #endregion
  227. #region 4 画IImageList 中的图标===================================================================
  228. int currt_X = e.Node.Bounds.X;
  229. if (treeView1.ImageList != null && treeView1.ImageList.Images.Count > 0)
  230. {
  231. //图标大小16*16
  232. Rectangle imagebox = new Rectangle(
  233. e.Node.Bounds.X - 3 - 16,
  234. e.Node.Bounds.Y + 3,
  235. 16,//IMAGELIST IMAGE WIDTH
  236. 16);//HEIGHT
  237. int index = e.Node.ImageIndex;
  238. string imagekey = e.Node.ImageKey;
  239. if (imagekey != "" && treeView1.ImageList.Images.ContainsKey(imagekey))
  240. e.Graphics.DrawImage(treeView1.ImageList.Images[imagekey], imagebox);
  241. else
  242. {
  243. if (e.Node.ImageIndex < 0)
  244. index = 0;
  245. else if (index > treeView1.ImageList.Images.Count - 1)
  246. index = 0;
  247. e.Graphics.DrawImage(treeView1.ImageList.Images[index], imagebox);
  248. }
  249. currt_X -= 19;
  250. }
  251. #endregion
  252. }
  253. catch(Exception ex)
  254. {
  255. }
  256. }
  257. #endregion
  258. //private void treeView1_KeyDown(object sender, KeyEventArgs e)
  259. //{
  260. // ArrowKeyUp = (e.KeyCode == Keys.Up);
  261. // if (e.KeyCode == Keys.Down)
  262. // {
  263. // Text = "Down";
  264. // }
  265. // ArrowKeyDown = (e.KeyCode == Keys.Down);
  266. // if (e.KeyCode == Keys.Up)
  267. // {
  268. // Text = "UP";
  269. // }
  270. //}
  271. private void treeView1_BeforeSelect(object sender, TreeViewCancelEventArgs e)
  272. {
  273. try
  274. {
  275. if (e.Node != null)
  276. {
  277. //禁止选中空白项
  278. if (e.Node.Text == "")
  279. {
  280. //响应上下键
  281. if (ArrowKeyUp)
  282. {
  283. if (e.Node.PrevNode != null && e.Node.PrevNode.Text != "")
  284. treeView1.SelectedNode = e.Node.PrevNode;
  285. }
  286. if (ArrowKeyDown)
  287. {
  288. if (e.Node.NextNode != null && e.Node.NextNode.Text != "")
  289. treeView1.SelectedNode = e.Node.NextNode;
  290. }
  291. e.Cancel = true;
  292. }
  293. }
  294. }
  295. catch(Exception ex)
  296. {
  297. }
  298. }
  299. private bool ArrowKeyUp = false;
  300. private bool ArrowKeyDown = false;
  301. private System.Windows.Forms.ImageList arrowImageList1;
  302. private Color m_SelectColor;
  303. private Color m_SelectColor2;
  304. private Color m_Color;
  305. private TreeView treeView1;
  306. }
  307. public class API
  308. {
  309. private const int WS_HSCROLL = 0x100000;
  310. private const int WS_VSCROLL = 0x200000;
  311. private const int GWL_STYLE = (-16);
  312. [DllImport("User32.dll")]
  313. public static extern IntPtr LoadCursor(IntPtr hInstance, CursorType cursor);
  314. [DllImport("user32.dll")]
  315. public static extern int GetWindowLong(IntPtr hwnd, int nIndex);
  316. [DllImport("user32.dll")]
  317. public static extern bool ShowScrollBar(IntPtr hWnd, int wBar, bool bShow);
  318. public const int WM_PRINTCLIENT = 0x0318;
  319. public const int PRF_CLIENT = 0x00000004;
  320. [DllImport("user32.dll")]
  321. public static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);
  322. /// <summary>
  323. /// 显示系统光标小手
  324. /// 像Win7非经典主题的小手光标
  325. /// </summary>
  326. public static Cursor Hand
  327. {
  328. get
  329. {
  330. IntPtr h = LoadCursor(IntPtr.Zero, CursorType.IDC_HAND);
  331. return new Cursor(h);
  332. }
  333. }
  334. public static bool IsWinXP
  335. {
  336. get
  337. {
  338. OperatingSystem OS = Environment.OSVersion;
  339. return (OS.Platform == PlatformID.Win32NT) &&
  340. ((OS.Version.Major > 5) || ((OS.Version.Major == 5) && (OS.Version.Minor == 1)));
  341. }
  342. }
  343. public static bool IsWinVista
  344. {
  345. get
  346. {
  347. OperatingSystem OS = Environment.OSVersion;
  348. return (OS.Platform == PlatformID.Win32NT) && (OS.Version.Major >= 6);
  349. }
  350. }
  351. /// <summary>
  352. /// 判断是否出现垂直滚动条
  353. /// </summary>
  354. /// <param name="ctrl">待测控件</param>
  355. /// <returns>出现垂直滚动条返回true,否则为false</returns>
  356. public static bool IsVerticalScrollBarVisible(Control ctrl)
  357. {
  358. if (!ctrl.IsHandleCreated)
  359. return false;
  360. return (GetWindowLong(ctrl.Handle, GWL_STYLE) & WS_VSCROLL) != 0;
  361. }
  362. /// <summary>
  363. /// 判断是否出现水平滚动条
  364. /// </summary>
  365. /// <param name="ctrl">待测控件</param>
  366. /// <returns>出现水平滚动条返回true,否则为false</returns>
  367. public static bool IsHorizontalScrollBarVisible(Control ctrl)
  368. {
  369. if (!ctrl.IsHandleCreated)
  370. return false;
  371. return (GetWindowLong(ctrl.Handle, GWL_STYLE) & WS_HSCROLL) != 0;
  372. }
  373. }
  374. public enum CursorType : uint
  375. {
  376. IDC_ARROW = 32512U,
  377. IDC_IBEAM = 32513U,
  378. IDC_WAIT = 32514U,
  379. IDC_CROSS = 32515U,
  380. IDC_UPARROW = 32516U,
  381. IDC_SIZE = 32640U,
  382. IDC_ICON = 32641U,
  383. IDC_SIZENWSE = 32642U,
  384. IDC_SIZENESW = 32643U,
  385. IDC_SIZEWE = 32644U,
  386. IDC_SIZENS = 32645U,
  387. IDC_SIZEALL = 32646U,
  388. IDC_NO = 32648U,
  389. //小手
  390. IDC_HAND = 32649U,
  391. IDC_APPSTARTING = 32650U,
  392. IDC_HELP = 32651U
  393. }
  394. }