Create Icons Using Code for TreeView

vendiddy

Well-known member
Joined
May 14, 2006
Messages
64
Programming Experience
1-3
Here is what I'm trying to do. For every new entry added to the TreeView, I want to give it an icon--a small colored circle. (The user picks the color.) How can I do this?

By the way are TreeView icons 16 x 16?

Thanks.
 
Images properties is controlled by the ImageList instance, default ImageSize is 16x16 max is 256x256. You can dynamically draw new images and add them to this collection (ImageList.Images which is a ImageCollection type), then set the index for the treenode. Read some in documentation about the methods of ImageCollection, it is great help for you to add images with a string key which you can later lookup by same key. Image keys is a new feature in .Net 2.0. For example you could name them 'red' 'green' 'blue' etc. since you only want one image of each color in the list.
 
Here is some sample code so you can see the basics, in designer I added these 4 controls: TreeView1, ImageList1, ComboBox1 and Button1. Then selected ImageList1 to be used for Treeview1.Imagelist property. I load colors into combobox, where user can select the circle color. If you add several new nodes with same color you see the same imageindex is used.
VB.NET:
Private Sub frmDiv_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) _
Handles MyBase.Load
  [COLOR=darkgreen]'list all color names into combobox1[/COLOR]
  Dim listColor As New List(Of Color)
  Dim c As Color
  For Each known As KnownColor In [Enum].GetValues(GetType(KnownColor))
    c = Color.FromKnownColor(known)
    If Not c.IsSystemColor Then listColor.Add(c)
  Next
  ComboBox1.DataSource = listColor
  ComboBox1.SelectedIndex = 3
End Sub
 
[COLOR=blue]'click button adds new treenode[/COLOR]
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) _
Handles Button1.Click
  [COLOR=darkgreen]'get a color[/COLOR]
  Dim c As Color = ComboBox1.SelectedItem
  [COLOR=darkgreen]'check if image exists[/COLOR]
  If Not ImageList1.Images.ContainsKey(c.Name) Then
    [COLOR=darkgreen]'draw and add to imagelist[/COLOR]
    Dim bmp As New Bitmap(16, 16) [SIZE=2][COLOR=#008000]'or: Dim bmp As New Bitmap(ImageList1.ImageSize.Width, ImageList1.ImageSize.Height)
[/COLOR][/SIZE]    Dim g As Graphics = Graphics.FromImage(bmp)
    Dim rctf As RectangleF = bmp.GetBounds(GraphicsUnit.Pixel)
    rctf.Inflate(-1, -1)
    g.DrawEllipse(New Pen(c), rctf)
    g.Dispose()
    ImageList1.Images.Add(c.Name, bmp)
  End If
  [COLOR=darkgreen]'get image index[/COLOR]
  Dim ix As Integer = ImageList1.Images.IndexOfKey(c.Name)
  [COLOR=darkgreen]'create treenode and add to treeview[/COLOR]
  Static nodeix As Integer
  nodeix += 1
  Dim nodetext As String = String.Format("node {0} imageindex {1}", nodeix.ToString, ix.ToString)
  Dim t As New TreeNode(nodetext, ix, ix)
  TreeView1.Nodes.Add(t)
End Sub
 
Thank you for the very helpful response. I have gotten this to work with my program, but I have a few more questions (I'm new to the VB.net object oriented programming thing):
  • I only want the top level nodes to have icons, but when I add a sub-level node, it obtains the icon of it's parent node. This happens even when I use myNode.Nodes.Add(theString). Right now, as a workaround, I'm just giving all the subnodes an icon with a transparent color.
  • Is List(Of X) just like an ArrayList except that only Objects of type X are allowed?
  • Does a static variable retain its value when the procedure is run again?
Thanks again, I probably wouldn't have been able to figure this out on my own.
 
1) By design, ie inherited unless overridden (workaround for you). Documentation: "The images referenced by the ImageIndex and SelectedImageIndex property values are the default images displayed by all the tree nodes that are assigned to the Nodes collection. Individual tree nodes can override the default images by setting the TreeNode.ImageIndex and TreeNode.SelectedImageIndex properties." These indexes are 0 as default for the Treeview, so as workaround you could add the first image as white or transparent and that image will be used for all nodes where you don't specifically set other image index.

2&3) yes & yes(class lifetime scope). For the future please ask unrelated questions (2&3) in separate threads, it help others seeking information and it helps you getting a dedicated answer without confusing mixed replies.
 
Last edited:
The tip in 1) leads me slightly off-topic too I'm afraid, my code to create the bitmap/image should for good OOP be placed in a separate function method, for instance:
VB.NET:
Function getimagecircle(ByVal c As Color) As Bitmap
  Dim bmp As New Bitmap(ImageList1.ImageSize.Width, ImageList1.ImageSize.Height)
  Dim g As Graphics = Graphics.FromImage(bmp)
  Dim rctf As RectangleF = bmp.GetBounds(GraphicsUnit.Pixel)
  rctf.Inflate(-1, -1)
  g.DrawEllipse(New Pen(c), rctf)
  g.Dispose()
  Return bmp
End Function
It much cleaner and easier to call in button click this instead:
VB.NET:
If Not ImageList1.Images.ContainsKey(c.Name) Then
  ImageList1.Images.Add(c.Name, getimagecircle(c))
End If
and also when adding the first white image (for example in form load):
VB.NET:
ImageList1.Images.Add(Color.White.Name, getimagecircle(Color.White))
 
Back
Top