如何在C#中的TreeView中显示多个复选框? [英] How to show multiple check boxes in a TreeView in C#?

查看:226
本文介绍了如何在C#中的TreeView中显示多个复选框?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我知道如何在TreeView中为每个TreeNode显示一个CheckBox。
我想在TreeView中显示每个TreeNode的3个复选框。
这是因为我的程序有3个图表,每个TreeNode代表一个不同的系列。我想给用户选择在他们喜欢的图表上显示每个系列。



这是(或类似的东西)吗?提前感谢。

解决方案

您需要拥有者绘制 TreeView 。不完全是最简单的所有者绘制一个控件的例子,但仍然不是太难。



以下是示例屏幕截图:





首先我们创建简单的 TreeNode 保存额外的数据:

  public class TreeNode3:TreeNode 
{
public string Label {get;组; }
public bool Check1 {get;组; }
public bool Check2 {get;组; }
public bool Check3 {get;组; }

public new string Text
{
get {return Label; }
set {Label = value; base.Text =; }
}

public TreeNode3(){}

public TreeNode3(string text){Label = text; }

public TreeNode3(string text,bool check1,bool check2,bool check3)
{
Label = text;
Check1 = check1; Check2 = check2; Check3 = check3;
}

public TreeNode3(string text,TreeNode3 [] children)
{
Label = text;
foreach(子节点中的TreeNode3节点)this.Nodes.Add(node);
}
}

请注意,我隐藏原始文本,通过字符串变量Label。我避免使用标签所以你仍然可以使用它自己..我没有实现所有的构造函数。如果您需要 ImageLists ,您可能需要添加 ImageIndices



现在 TreeView 本身:

 使用系统.Windows.Forms.VisualStyles; 
// ..

public partial class UcTreeView:TreeView
{
[DisplayName(Checkbox Spacing),CategoryAttribute(Appearance),
描述(复选框之间的像素数。]]
public int Spacing {get;组; }

[DisplayName(Text Padding),CategoryAttribute(Appearance),
描述(Left padding of text。]]
public int LeftPadding {get;组; }



public UcTreeView()
{
InitializeComponent();
DrawMode = TreeViewDrawMode.OwnerDrawText;
HideSelection = false; //我喜欢那个更好的
CheckBoxes = false; //必要的!
FullRowSelect = false; //必要的!
Spacing = 4; // default checkbox spacing
LeftPadding = 7; //默认文本填充
}

public TreeNode3 AddNode(string label,bool check1,bool check2,bool check3)
{
TreeNode3 node = new TreeNode3 ,check1,check2,check3);
this.Nodes.Add(node);
return node;
}

private Size glyph = Size.Empty;

protected override void OnDrawNode(DrawTreeNodeEventArgs e)
{
TreeNode3 n = e.Node as TreeNode3;
if(n == null){e.DrawDefault = true;返回; }

CheckBoxState cbsTrue = CheckBoxState.CheckedNormal;
CheckBoxState cbsFalse = CheckBoxState.Unc checkededNormal;

Rectangle rect = new Rectangle(e.Bounds.Location,
new Size(ClientSize.Width,e.Bounds.Height));
glyph = CheckBoxRenderer.GetGlyphSize(e.Graphics,cbsTrue);
int offset = glyph.Width * 3 + Spacing * 2 + LeftPadding;

if(n.IsSelected)
{
e.Graphics.FillRectangle(SystemBrushes.MenuHighlight,rect);
e.Graphics.DrawString(n.Label,Font,Brushes.White,
e.Bounds.X + offset,e.Bounds.Y);
}
else
{
CheckBoxRenderer.DrawParentBackground(e.Graphics,e.Bounds,this);
e.Graphics.DrawString(n.Label,Font,Brushes.Black,
e.Bounds.X + offset,e.Bounds.Y);
}

CheckBoxState bs1 = n.Check1? cbsTrue:cbsFalse;
CheckBoxState bs2 = n.Check2? cbsTrue:cbsFalse;
CheckBoxState bs3 = n.Check3? cbsTrue:cbsFalse;

CheckBoxRenderer.DrawCheckBox(e.Graphics,cbx(e.Bounds,0).Location,bs1);
CheckBoxRenderer.DrawCheckBox(e.Graphics,cbx(e.Bounds,1).Location,bs2);
CheckBoxRenderer.DrawCheckBox(e.Graphics,cbx(e.Bounds,2).Location,bs3);

}

protected override void OnNodeMouseClick(TreeNodeMouseClickEventArgs e)
{
Console.WriteLine(e.Location +bounds:+ e.Node .Bounds);

TreeNode3 n = e.Node as TreeNode3;
if(e == null)return;

if(cbx(n.Bounds,0).Contains(e.Location))n.Check1 =!n.Check1;
else if(cbx(n.Bounds,1).Contains(e.Location))n.Check2 =!n.Check2;
else if(cbx(n.Bounds,2).Contains(e.Location))n.Check3 =!n.Check3;
else
{
if(SelectedNode == n& Control.ModifierKeys == Keys.Control)
SelectedNode = SelectedNode!= null? null:n;
else SelectedNode = n;
}

Console.WriteLine(+ n.Check1 ++ n.Check2 ++ n.Check3);

Invalidate();

}


矩形cbx(Rectangle bounds,int check)
{
return new Rectangle(bounds.Left + 2 + glyph.Width + Spacing)* check,
bounds.Y + 2,glyph.Width,glyph.Height);
}

}

>


  • 树不支持 LabelEditing

  • 该树不支持 FullrowSelect 为true,但实际上它仍然有效。

  • 您应该可以使用 ImageList StateImageList

  • 不要将 CheckBoxes 属性设置为true!所有三个 CheckBoxes 都是虚拟的,并且在将节点转换为 TreeNode3 作为 Check1 ..Check3 属性!

  • 我没有实现3状态复选框。您可以将bools更改为可空,然后添加点击和绘制事件中所需的代码。

  • 我已经留了几个 Console.WriteLines 我添加了一个<$ c $ 。 c> Spacing Padding 属性和几个构造函数。
    现在,设置示例的表单代码看起来很正常:

      ucTreeView1.Nodes.Add(new TreeNode3 Bauhaus,true,true,false)); 
    TreeNode3 aNode = ucTreeView1.AddNode(Beatles,true,true,false);
    ucTreeView1.Nodes.Add(new TreeNode3(Blur,true,true,false));
    ucTreeView1.Nodes.Add(new TreeNode3(Byrds,true,true,false));
    ucTreeView1.Nodes.Add(new TreeNode3(Bee Gees,new TreeNode3 [] {
    new TreeNode3(Barry,true,false,false),
    new TreeNode3 ),
    new TreeNode3(Maurice)}));

    TreeNode3 aNodeA = new TreeNode3(John,true,true,false);
    TreeNode3 aNodeB = new TreeNode3(Paul,true,true,true);
    TreeNode3 aNodeC = new TreeNode3(George,true,false,true);
    TreeNode3 aNodeD = new TreeNode3(Ringo,true,false,false);

    aNode.Nodes.Add(aNodeA);
    aNode.Nodes.Add(aNodeB);
    aNode.Nodes.Add(aNodeC);
    aNode.Nodes.Add(aNodeD);


    I know how to show a single CheckBox for each TreeNode in a TreeView. I would like to show 3 CheckBoxes for each TreeNode in a TreeView. The reason for this is that there are 3 charts in my program, and each TreeNode represents a different series. I would like to give the user the option of displaying each series on whichever chart they like.

    Is this (or something similar) possible? Thanks in advance.

    解决方案

    You will need to owner-draw a TreeView. Not exactly the simplest example of owner-drawing a Control but still not too hard.

    Here is an example screenshot:

    First we create simple TreeNode subclass to hold the extra data:

    public class TreeNode3 : TreeNode
    {
        public string Label { get; set; }
        public bool Check1 { get; set; }
        public bool Check2 { get; set; }
        public bool Check3 { get; set; }
    
        public new string Text
        {
            get { return Label; }
            set { Label = value; base.Text = ""; }
        }
    
        public TreeNode3()   { }
    
        public TreeNode3(string text)   { Label = text; }
    
        public TreeNode3(string text, bool check1, bool check2, bool check3)
        {
            Label = text;
            Check1 = check1; Check2 = check2; Check3 = check3;
        }
    
        public TreeNode3(string text, TreeNode3[] children)
        {
            Label = text;
            foreach (TreeNode3 node in children) this.Nodes.Add(node);
        }
    }
    

    Note that I hide the original Text and basically replace it by a string variable Label. I avoid using the Tag so you can still make use of it yourself.. I have not implemented all constructors. If you need ImageLists you may want to add those with the ImageIndices.

    Now for the TreeView itself:

    using System.Windows.Forms.VisualStyles;
    //..
    
    public partial class UcTreeView : TreeView
    {
        [DisplayName("Checkbox Spacing"),  CategoryAttribute("Appearance"),
         Description("Number of pixels between the checkboxes.")]
        public int Spacing { get; set; }
    
        [DisplayName("Text Padding"), CategoryAttribute("Appearance"), 
         Description("Left padding of text.")]
        public int LeftPadding { get; set; }
    
    
    
        public UcTreeView()
        {
            InitializeComponent();
            DrawMode = TreeViewDrawMode.OwnerDrawText;
            HideSelection = false;    // I like that better
            CheckBoxes = false;       // necessary!
            FullRowSelect = false;    // necessary!
            Spacing = 4;              // default checkbox spacing
            LeftPadding = 7;          // default text padding
        }
    
        public TreeNode3 AddNode(string label, bool check1, bool check2, bool check3)
        {
            TreeNode3 node = new TreeNode3(label, check1, check2, check3);
            this.Nodes.Add(node);
            return node;
        }
    
        private  Size glyph = Size.Empty;
    
        protected override void OnDrawNode(DrawTreeNodeEventArgs e)
        {
            TreeNode3 n = e.Node as TreeNode3;
            if (n == null) { e.DrawDefault = true; return; }
    
            CheckBoxState cbsTrue = CheckBoxState.CheckedNormal;
            CheckBoxState cbsFalse = CheckBoxState.UncheckedNormal;
    
            Rectangle rect = new Rectangle(e.Bounds.Location, 
                                 new Size(ClientSize.Width, e.Bounds.Height));
            glyph = CheckBoxRenderer.GetGlyphSize(e.Graphics, cbsTrue );
            int offset = glyph.Width * 3 + Spacing * 2 + LeftPadding;
    
            if (n.IsSelected)
            {
                e.Graphics.FillRectangle(SystemBrushes.MenuHighlight ,rect);
                e.Graphics.DrawString(n.Label, Font, Brushes.White, 
                                      e.Bounds.X + offset, e.Bounds.Y);
            }
            else
            {
                CheckBoxRenderer.DrawParentBackground(e.Graphics, e.Bounds, this);
                e.Graphics.DrawString(n.Label, Font, Brushes.Black, 
                                      e.Bounds.X + offset, e.Bounds.Y);
            }
    
            CheckBoxState bs1 = n.Check1 ? cbsTrue : cbsFalse;
            CheckBoxState bs2 = n.Check2 ? cbsTrue : cbsFalse;
            CheckBoxState bs3 = n.Check3 ? cbsTrue : cbsFalse;
    
            CheckBoxRenderer.DrawCheckBox(e.Graphics,  cbx(e.Bounds, 0).Location, bs1);
            CheckBoxRenderer.DrawCheckBox(e.Graphics,  cbx(e.Bounds, 1).Location, bs2);
            CheckBoxRenderer.DrawCheckBox(e.Graphics,  cbx(e.Bounds, 2).Location, bs3);
    
        }
    
        protected override void OnNodeMouseClick(TreeNodeMouseClickEventArgs e)
        {
            Console.WriteLine(e.Location + " bounds:"  + e.Node.Bounds);
    
            TreeNode3 n = e.Node as TreeNode3;
            if (e == null) return;
    
            if      (cbx(n.Bounds, 0).Contains(e.Location)) n.Check1 = !n.Check1;
            else if (cbx(n.Bounds, 1).Contains(e.Location)) n.Check2 = !n.Check2;
            else if (cbx(n.Bounds, 2).Contains(e.Location)) n.Check3 = !n.Check3;
            else
            {
                if (SelectedNode == n && Control.ModifierKeys == Keys.Control)
                     SelectedNode = SelectedNode != null ? null : n;
                else SelectedNode = n;
            }
    
            Console.WriteLine(" " + n.Check1 + " " + n.Check2 +" " + n.Check3 );
    
            Invalidate();
    
        }
    
    
        Rectangle cbx(Rectangle bounds, int check)
        {
            return new Rectangle(bounds.Left + 2 + (glyph.Width + Spacing) * check, 
                                 bounds.Y + 2, glyph.Width, glyph.Height);
        }
    
    }
    

    A few notes:

    • The tree does not support LabelEditing. Doable but another can of worms..
    • The tree does not support FullrowSelect to be true but actually it is in effect anyway..
    • You should be able to use ImageList and StateImageList but need to set the indices after the nodes are added.
    • Do not set the CheckBoxes property to true! All three CheckBoxes are virtual and you access them after casting the nodes to TreeNode3 as its Check1..Check3 properties!
    • I have not implemented 3-State CheckBoxes. You could change the bools to be nullable and then add the code needed in the click and draw events.
    • I have left a few Console.WriteLines in the code for better testing..

    Update I have added a Spacing and Padding property and a few constructors. Now the form code that sets up the example looks pretty normal:

    ucTreeView1.Nodes.Add(new TreeNode3("Bauhaus", true, true, false));
    TreeNode3 aNode = ucTreeView1.AddNode("Beatles", true, true, false);
    ucTreeView1.Nodes.Add(new TreeNode3("Blur", true, true, false));
    ucTreeView1.Nodes.Add(new TreeNode3("Byrds", true, true, false));
    ucTreeView1.Nodes.Add(new TreeNode3("Bee Gees", new TreeNode3[]{
        new TreeNode3("Barry", true, false, false),
        new TreeNode3("Robin"),  
        new TreeNode3("Maurice")} ));
    
    TreeNode3 aNodeA = new TreeNode3("John",   true, true,  false);
    TreeNode3 aNodeB = new TreeNode3("Paul",   true, true,  true);
    TreeNode3 aNodeC = new TreeNode3("George", true, false, true);
    TreeNode3 aNodeD = new TreeNode3("Ringo",  true, false, false);
    
    aNode.Nodes.Add(aNodeA);
    aNode.Nodes.Add(aNodeB);
    aNode.Nodes.Add(aNodeC);
    aNode.Nodes.Add(aNodeD);
    

    这篇关于如何在C#中的TreeView中显示多个复选框?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆