zoukankan      html  css  js  c++  java
  • 定制TreeView控件,实现节点样式自定义及节点级别的单选、复选

    需求

    在项目中需要对TreeView进行定制,要求比较简单,主要要求如下:

    1.  每个节点被造中时可以有自己的事件
    2. Winform中TreeView控件默认只支持树级别的CheckBox,再要求支持节点级别的CheckBox/RadioButton,即能为每个节点设置支不支持选择,选择的样式是复选还是单选。
    3. Winform中TreeView控件节点的默认显示样式是“CheckBox"+ “图片”+“节点文字”,现要求互换“CheckBox”和“图片”的位置,显示样式改为“图片”+“CheckBox”+“节点文字”。

    总体显示效果如下图:

    设计思路

    TreeView控件有DrawMode属性,我们需要定义一个继承自TreeView的类(这里叫GTreeView吧),并在GTreeView的构造函数里设置DrawMode =TreeViewDrawMode .OwnerDrawText,以告诉系统我们需要自己绘制文字。然后在GTreeView的DrawNode事件中根据GTreeNode的CheckBoxVisible,CheckBoxStyle属性来先绘制选择框,这里的选择框实际上是一个图片,根据属性的不同决定是不绘制还是绘制RadioButtonChecked/RadioButtonUnchecked/CheckBoxChecked/CheckBoxUnchecked中的一个,绘制完图片后再绘制节点文本。

    GTreeNode继承于TreeNode,主要添加了CheckBoxVisible, CheckBoxStyle属性和NodeSelected事件,新增加属性和事件的用途见名知义,不多解释。

    Override TreeView的MouseUp事件,判断如果Mouse落后在选择框图片内,则改变节点的选中状态并重绘树,需要注意如果是单选节点的话还需要清空兄弟节点的选中状态,因为同一个父节点下只允许一个单选节点为选中状态。

    Override TreeView的AfterSelected事件,如果当前选中的节点有NodeSelected EventHanlder则直接调用并返回,否则调用AfterSelected的默认处理。

    代码

    TreeView Code
    using System;
    using System.Collections.Generic;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Windows.Forms;
    using CustomTreeView.Properties;

    namespace GADPlatSystem.Tools
    {
    /// <summary>
    /// 自定义TreeView控件,支持节点级别的复选、单选;
    /// 节点显示样式改为Icon+CheckBox+NodeText的样式
    /// </summary>
    public class GTreeView : TreeView
    {
    #region Private Variables

    private const int checkBoxImageWidth = 16;
    private const int checkBoxImageHeight = 16;
    private Image imgChecked;
    private Image imgUnchecked;
    private Image imgRBChecked;
    private Image imgRBUnchecked;
    private System.ComponentModel.IContainer components;
    #endregion

    #region Constructs
    public GTreeView()
    {
    InitializeComponent();

    // 初始化CheckBox相关的图片
    imgUnchecked = Resource.TreeNodeUnchecked;
    imgChecked
    = Resource.TreeNodeChecked;
    imgRBUnchecked
    = Resource.TreeNodeRBUnchecked;
    imgRBChecked
    = Resource.TreeNodeRBChecked;

    // 设置TreeView为自己绘制文本和图标并绑定相关的事件
    this.DrawMode = TreeViewDrawMode.OwnerDrawText;
    this.DrawNode += new DrawTreeNodeEventHandler(GTreeView_DrawNode);
    this.MouseUp += new MouseEventHandler(GTreeView_MouseUp);
    }

    #endregion

    #region Event Hanlder Methods

    /// <summary>
    /// 判断如果点击的是Checkbox图片,则改变节点的IsCheck属性值
    /// 需要注意的是同一父节点下只允许一个RadioButton类型的节点为选中状态
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    void GTreeView_MouseUp(object sender, MouseEventArgs e)
    {
    GTreeNode node
    = GetNodeAt(e.X, e.Y) as GTreeNode;
    if (node == null || !node.CheckBoxVisible)
    {
    return;
    }
    Rectangle checkboxImgRect
    = new Rectangle(node.Bounds.X, node.Bounds.Y, checkBoxImageWidth, checkBoxImageHeight); //节点区域

    // 如果点击的是checkbox图片
    if (checkboxImgRect.Contains(e.X, e.Y))
    {
    node.Checked
    = !node.Checked;

    // 如果是单选,则设置同级别的其它单选项为unchecked.
    if (node.Parent != null && node.CheckBoxStyle == GTreeNode.CheckBoxStyleEnum.RadioButton)
    {
    foreach (TreeNode siblingNode in node.Parent.Nodes)
    {
    var siblingGNode
    = siblingNode as GTreeNode;
    if (siblingGNode == null)
    {
    continue;
    }
    if (siblingGNode.Name != node.Name && siblingGNode.CheckBoxStyle == GTreeNode.CheckBoxStyleEnum.RadioButton && siblingGNode.Checked)
    {
    siblingGNode.Checked
    = false;
    }

    }
    }
    }
    }

    /// <summary>
    /// 绘制节点的图标和文字,样式为Icon+CheckBox+NodeText
    /// Checkbox支持节点级别的单选、复选
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    void GTreeView_DrawNode(object sender, DrawTreeNodeEventArgs e)
    {
    GTreeNode node
    = e.Node as GTreeNode;
    if (node == null)
    {
    return;
    }

    Rectangle nodeRect
    = e.Node.Bounds;

    // 如果需要显示CheckBox,则绘制
    if (node.CheckBoxVisible)
    {
    Point drawPt
    = new Point(nodeRect.Location.X, nodeRect.Location.Y); //绘制图标的起始位置
    Size imgSize = new Size(checkBoxImageWidth, checkBoxImageHeight); //图片大小
    Rectangle imgRect = new Rectangle(drawPt, imgSize);

    if (e.Node.Checked)
    {
    if (node.CheckBoxStyle == GTreeNode.CheckBoxStyleEnum.CheckBox)
    {
    e.Graphics.DrawImage(imgChecked, imgRect);
    }
    else
    {
    e.Graphics.DrawImage(imgRBChecked, imgRect);

    }
    }
    else
    {
    if (node.CheckBoxStyle == GTreeNode.CheckBoxStyleEnum.CheckBox)
    {
    e.Graphics.DrawImage(imgUnchecked, imgRect);
    }
    else
    {
    e.Graphics.DrawImage(imgRBUnchecked, imgRect);
    }
    }
    }



    //-----------------------绘制文本 -------------------------------
    Rectangle textRec;
    if (node.CheckBoxVisible)
    {
    textRec
    = new Rectangle(nodeRect.X + checkBoxImageWidth + 2, nodeRect.Y, nodeRect.Width, nodeRect.Height);
    }
    else
    {
    textRec
    = nodeRect;
    }

    Font nodeFont
    = e.Node.NodeFont;
    if (nodeFont == null)
    nodeFont
    = ((TreeView)sender).Font;
    Brush textBrush
    = SystemBrushes.WindowText;

    if ((e.State & TreeNodeStates.Focused) != 0)
    {
    e.Graphics.FillRectangle(SystemBrushes.Highlight, textRec);
    }
    e.Graphics.DrawString(e.Node.Text, nodeFont, textBrush, Rectangle.Inflate(textRec,
    2, 0));


    }

    /// <summary>
    /// 节点被选中后,如果节点有事件处理程序,则调用
    /// </summary>
    /// <param name="e"></param>
    protected override void OnAfterSelect(TreeViewEventArgs e)
    {
    var gNode
    = e.Node as GTreeNode;
    if (gNode != null && gNode.NodeSelected != null)
    {
    TreeViewEventArgs arg
    = new TreeViewEventArgs(e.Node);
    gNode.NodeSelected(
    this, arg);
    return;
    }
    base.OnAfterSelect(e);
    }

    #endregion

    #region Private Methods
    private void InitializeComponent()
    {
    this.SuspendLayout();
    //
    // GTreeView
    //
    this.LineColor = System.Drawing.Color.Black;
    this.ResumeLayout(false);

    }
    #endregion

    }
    }
  • 相关阅读:
    窗体吸附 Timer + 判断Location (简单实用)
    C# FTP 应用程序
    C# 加密方法汇总
    LINQ 标准的查询操作符 合计操作符 Count()、Sum()、Min()、Max()、Average()和Aggregate()
    委托中的协变和逆变(C# 编程指南)
    深入探讨C#序列化和反序列化
    grep 命令详解
    Oracle 数据库的启动和关闭的方式!
    linux 下的光盘拷贝
    C3P0连接池配置
  • 原文地址:https://www.cnblogs.com/zhangronghua/p/CustomTreeView.html
Copyright © 2011-2022 走看看