如何在C#中的TreeView中显示多个复选框? [英] How to show multiple check boxes in a TreeView in C#?
问题描述
我知道如何在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 $ 。 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 needImageLists
you may want to add those with theImageIndices
.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
andStateImageList
but need to set the indices after the nodes are added. - Do not set the
CheckBoxes
property to true! All threeCheckBoxes
are virtual and you access them after casting the nodes toTreeNode3
as itsCheck1..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
andPadding
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屋!
- The tree does not support