C# winform绘制自定义TreeView,仿H5

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/haoranhaoshi/article/details/82978978

NewTreeView.cs:

public partial class NewTreeView : TreeView
    {
        Color backColor = Color.FromArgb(227, 251, 244);        
        Font foreFont = new Font("微软雅黑", 9F, FontStyle.Bold);

        Brush foreBrush = new SolidBrush(Color.FromArgb(81, 81, 81));        
        Brush recBrush = new SolidBrush(Color.FromArgb(82, 218, 163));
        Brush recSelectedBrush = new SolidBrush(Color.FromArgb(248, 248, 255));

        Pen recPen = new Pen(new SolidBrush(Color.FromArgb(226, 226, 226)));
        Pen recHoverPen = new Pen(new SolidBrush(Color.FromArgb(82, 218, 163)));
        Pen linePen = new Pen(Color.FromArgb(226, 226, 226), 1);

        Image icon;

        public NewTreeView()
        {
            InitializeComponent();

            this.DrawMode = TreeViewDrawMode.OwnerDrawAll;
            this.ItemHeight = 30;//节点行高          
            this.BackColor = backColor;
            this.ShowLines = true;
            this.HotTracking = true;
            this.Indent = 20;//节点X值缩进量
            this.Scrollable = true;
            this.BorderStyle = BorderStyle.None;
            this.Font = foreFont;
        }

        protected override void OnDrawNode(DrawTreeNodeEventArgs e)
        {                
            if (e.Node.Level == 0)//根节点
            {                
                if (!e.Node.IsExpanded)//根节点未展开
                {
                    icon = Resources.list_plus;                    
                }
                else//根节点展开
                {      
                    icon = Resources.list_zhankai;                    
                }
                //刷新背景色防止字体图标重绘叠加
                e.Graphics.FillRectangle(new SolidBrush(Color.FromArgb(227, 251, 244)), e.Bounds);
                //重绘图标,一级节点X值默认为23,padding-left为6,17 = 23 - 6
                e.Graphics.DrawImage(icon, e.Node.Bounds.X - 17, e.Node.Bounds.Y + 5);                    
                //重绘字体
                e.Graphics.DrawString(e.Node.Text, foreFont, foreBrush, e.Node.Bounds.Left + 16, e.Node.Bounds.Top + 4);
            }
            else
            {
                if (!e.Bounds.IsEmpty)//如果子节点的Bounds属性不为空(Empty),绘制该节点
                {
                    e.Graphics.FillRectangle(Brushes.White, e.Bounds);

                    //绘制连接线,30 = 20 + 10,10为图标宽的一半,保证topEnd点在图标中心,15为行高一半
                    Point start = new Point(e.Node.Bounds.X + 15, e.Node.Bounds.Y + 15);
                    Point middle = new Point(e.Node.Bounds.X - 30, e.Node.Bounds.Y + 15);
                    Point topEnd = new Point(e.Node.Bounds.X - 30, e.Node.Bounds.Y);
                    Point bottomEnd = new Point(e.Node.Bounds.X - 30, e.Node.Bounds.Y + 30);
                    e.Graphics.DrawLine(linePen, start, middle);
                    e.Graphics.DrawLine(linePen, middle, topEnd);
                    if(null != e.Node.NextNode)
                    {
                        e.Graphics.DrawLine(linePen, middle, bottomEnd);
                    }

                    //绘制文本框,宽145px可容纳十个10.5pt的字,55 = 23 + 20 + 12,文本框距离上下边界4px
                    Rectangle box = new Rectangle(e.Bounds.Left + 55, e.Bounds.Top + 4, this.Width - 55 - 25, e.Bounds.Height - 8);                    
                                                            
                    if (e.Node.IsSelected)//二级节点被选中
                    {
                        e.Graphics.FillRectangle(recBrush, box);
                        e.Graphics.DrawString(e.Node.Text, foreFont, recSelectedBrush, e.Node.Bounds.Left + 12, e.Node.Bounds.Top + 4);
                    }
                    else
                    {
                        if ((e.State & TreeNodeStates.Hot) != 0)//鼠标指针在二级节点上
                        {
                            e.Graphics.DrawRectangle(recHoverPen, box);                            
                        }
                        else
                        {
                            e.Graphics.DrawRectangle(recPen, box); 
                        }
                        e.Graphics.DrawString(e.Node.Text, foreFont, foreBrush, e.Node.Bounds.Left + 12, e.Node.Bounds.Top + 4);                          
                    }                    
                }
            }            
            
        }

        protected override void OnMouseClick(MouseEventArgs e)
        {
            base.OnMouseClick(e);
            TreeNode tn = this.GetNodeAt(e.Location);
            if(0 != tn.Level)//点击一级节点不使二级节点的选中效果消失
            {
                this.SelectedNode = tn;
            }            
            
            //图标中心点向右的区域也能单击折叠与展开
            Rectangle bounds = new Rectangle(tn.Bounds.Left - 17, tn.Bounds.Y, tn.Bounds.Width - 16, tn.Bounds.Height);
            if (tn != null && bounds.Contains(e.Location) == false)
            {
                if (tn.IsExpanded == false)
                    tn.Expand();
                else
                    tn.Collapse();
            }
        }

        TreeNode currentNode = null;
        protected override void OnMouseMove(MouseEventArgs e)
        {
            base.OnMouseMove(e);
            TreeNode tn = this.GetNodeAt(e.Location);
            Graphics g = this.CreateGraphics();
            if (currentNode != tn)
            {                
                //绘制当前节点的hover背景
                if (null != tn)
                {
                    OnDrawNode(new DrawTreeNodeEventArgs(g, tn, new Rectangle(0, tn.Bounds.Y, this.Width - 4, tn.Bounds.Height), TreeNodeStates.Hot));                                                              
                }
                
                //取消之前hover的节点背景
                if (null != currentNode)
                {
                    OnDrawNode(new DrawTreeNodeEventArgs(g, currentNode, new Rectangle(0, currentNode.Bounds.Y, this.Width - 4, currentNode.Bounds.Height), TreeNodeStates.Default));                    
                }
            }
            currentNode = tn;
            g.Dispose();//释放Graphics资源
        }

        protected override void OnMouseLeave(EventArgs e)
        {
            base.OnMouseLeave(e);
            //移出控件时取消Hover背景
            if (currentNode != null)
            {
                Graphics g = this.CreateGraphics();
                OnDrawNode(new DrawTreeNodeEventArgs(g, currentNode, new Rectangle(0, currentNode.Bounds.Y, this.Width - 4, currentNode.Bounds.Height), TreeNodeStates.Default));

				currentNode = null;//同一个节点Leave后Move有Hover效果            
		    }
        }



        protected override void OnMouseDoubleClick(MouseEventArgs e)
        {
            base.OnMouseDoubleClick(e);
            TreeNode tn = this.GetNodeAt(e.Location);
            ////图标中心点向右的区域双击折叠与展开
            Rectangle bounds = new Rectangle(tn.Bounds.Left - 17, tn.Bounds.Y, tn.Bounds.Width - 16, tn.Bounds.Height);
            if (tn != null && bounds.Contains(e.Location) == false)
            {
                if (tn.IsExpanded == false)
                    tn.Expand();
                else
                    tn.Collapse();
            }
        }

    }

NewTreeView.Designer.cs:

partial class NewTreeView
    {
        /// <summary> 
        /// 必需的设计器变量。
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary> 
        /// 清理所有正在使用的资源。
        /// </summary>
        /// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region 组件设计器生成的代码

        /// <summary> 
        /// 设计器支持所需的方法 - 不要
        /// 使用代码编辑器修改此方法的内容。
        /// </summary>
        private void InitializeComponent()
        {
            this.SuspendLayout();
            // 
            // NewTreeView
            // 
            this.ResumeLayout(false);
        }

        #endregion
    }

猜你喜欢

转载自blog.csdn.net/haoranhaoshi/article/details/82978978