Solved

Images in a TreeView

Posted on 2003-12-04
30
981 Views
Last Modified: 2008-02-01
Hi, I've got the following problem.

I'm looking forward to add a second image to a TreeView node, that indicates the status of the node (something like the small images that appears in MSVStudio .NET when you have it integrated with source safe (a lock if it is checked in, or a tick if it is checked out).

Only this kind of solution will be valid.

In order to have a more accurate of what I'm talking about check

http://es.geocities.com/n101noemi/TreeNode.jpg


Is there any way to achieve it? And in case there is, how?

Thanks a lot

Tincho
0
Comment
Question by:tinchos
  • 13
  • 9
  • 8
30 Comments
 
LVL 9

Expert Comment

by:malharone
ID: 9877077
Public Class Form2
    Inherits System.Windows.Forms.Form

#Region " Windows Form Designer generated code "

    Public Sub New()
        MyBase.New()

        'This call is required by the Windows Form Designer.
        InitializeComponent()

        'Add any initialization after the InitializeComponent() call

    End Sub

    'Form overrides dispose to clean up the component list.
    Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
        If disposing Then
            If Not (components Is Nothing) Then
                components.Dispose()
            End If
        End If
        MyBase.Dispose(disposing)
    End Sub

    'Required by the Windows Form Designer
    Private components As System.ComponentModel.IContainer

    'NOTE: The following procedure is required by the Windows Form Designer
    'It can be modified using the Windows Form Designer.  
    'Do not modify it using the code editor.
    Friend WithEvents TreeView1 As System.Windows.Forms.TreeView
    Friend WithEvents ImageList1 As System.Windows.Forms.ImageList
    <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
        Me.components = New System.ComponentModel.Container
        Dim resources As System.Resources.ResourceManager = New System.Resources.ResourceManager(GetType(Form2))
        Me.TreeView1 = New System.Windows.Forms.TreeView
        Me.ImageList1 = New System.Windows.Forms.ImageList(Me.components)
        Me.SuspendLayout()
        '
        'TreeView1
        '
        Me.TreeView1.ImageIndex = -1
        Me.TreeView1.Location = New System.Drawing.Point(8, 8)
        Me.TreeView1.Name = "TreeView1"
        Me.TreeView1.SelectedImageIndex = -1
        Me.TreeView1.Size = New System.Drawing.Size(208, 176)
        Me.TreeView1.TabIndex = 0
        '
        'ImageList1
        '
        Me.ImageList1.ImageSize = New System.Drawing.Size(16, 16)
        Me.ImageList1.ImageStream = CType(resources.GetObject("ImageList1.ImageStream"), System.Windows.Forms.ImageListStreamer)
        Me.ImageList1.TransparentColor = System.Drawing.Color.Transparent
        '
        'Form2
        '
        Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13)
        Me.ClientSize = New System.Drawing.Size(292, 266)
        Me.Controls.Add(Me.TreeView1)
        Me.Name = "Form2"
        Me.Text = "Form2"
        Me.ResumeLayout(False)

    End Sub

#End Region

    Private Sub Form2_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Me.TreeView1.ImageList = Me.ImageList1
        Dim tn1, tn2, tn3 As TreeNode
        tn1 = New TreeNode("C:\", 0, 0)
        tn2 = New TreeNode("Windows", 1, 1)
        tn3 = New TreeNode("Program Files", 2, 2)

        tn1.Nodes.Add(tn2)
        tn1.Nodes.Add(tn3)
        Me.TreeView1.Nodes.Add(tn1)

    End Sub
End Class
0
 
LVL 96

Expert Comment

by:Bob Learned
ID: 9877083
Do you know what an ImageList is and how to use it?  I don't know the specific syntax for C#, mostly a VB programmer, but I could help, but I don't have much time to work out the specifics now.  Just something to get you started.
0
 
LVL 9

Author Comment

by:tinchos
ID: 9877149
malharone,

I dont have problems with the image

Apart from that, I quite don't see which is the part of your code supposed to add the other image.



TheLearnedOne,

Yes, I do know how to use an ImageList, in fact I'm using it, what I don't know is how to add this second image to the node of the treeview.

Thanks

Tincho
0
 
LVL 9

Expert Comment

by:malharone
ID: 9877157
image list is a form control .... so from the tool box, find the imagelist, and drag it into your form. once you do that, then go to the imagelist properties, and add images to the images collection.
0
 
LVL 96

Expert Comment

by:Bob Learned
ID: 9877180
Oooh, now I understand.  You want 2 images for one node.  I didn't get that one right away.  You could do an owner-drawn tree view (ugly!), or you could use an one image that has 2 parts to indicate both the type and the state.
0
 
LVL 9

Author Comment

by:tinchos
ID: 9877181
Just in order to clarify.

What I'm looking forward to is to add have 2 images for the node.

The original one and the new 'status' one.

As in the image.

Tincho
0
 
LVL 9

Expert Comment

by:malharone
ID: 9877211
"Apart from that, I quite don't see which is the part of your code supposed to add the other image."??

i added images into my imagelist using the UI -- property builder.
and then using "Me.TreeView1.ImageList = Me.ImageList1" or "this.TreeView1.ImageList = this.ImageList1;", i assigned the imagelist to the treeview control in the form.

in the following line, i construct the node. the constructor i used is:
sub new (node_label_text, image_index, selected_index)
node_label_text: should be obvious ... it's a string that's displayed as the label
image_index: is the index of the image from the image list which is used to display the image when the focus is NOT on that node
selected_index: is the index of the image from the image list which is used to display the image when the focus IS on that node -- when the node is selected.

in my example below, i've used 0,0 or 1,1 or 2,2 .. since i want the same image displayed wether the node is selected or not.
tn1 = New TreeNode("C:\", 0, 0)
0
 
LVL 9

Author Comment

by:tinchos
ID: 9877220
TheLearnedOne

Yeap, that's a possible approach, I had that in mind, but.......

suppose that in the treeview you have 4 different images and then you have 5 different states.....

then I would have to have so many images as the combination of them (20 different images)

as the number of states can grow and the number of different images also, it's not acceptable.

Tincho
0
 
LVL 9

Expert Comment

by:malharone
ID: 9877245
you can't really display two different images for single node. what you can do is display an image for one status, and when the status changes change the imageindex and selectedimageindex properties.


Public Class Form2
    Inherits System.Windows.Forms.Form

#Region " Windows Form Designer generated code "

    Public Sub New()
        MyBase.New()

        'This call is required by the Windows Form Designer.
        InitializeComponent()

        'Add any initialization after the InitializeComponent() call

    End Sub

    'Form overrides dispose to clean up the component list.
    Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
        If disposing Then
            If Not (components Is Nothing) Then
                components.Dispose()
            End If
        End If
        MyBase.Dispose(disposing)
    End Sub

    'Required by the Windows Form Designer
    Private components As System.ComponentModel.IContainer

    'NOTE: The following procedure is required by the Windows Form Designer
    'It can be modified using the Windows Form Designer.  
    'Do not modify it using the code editor.
    Friend WithEvents TreeView1 As System.Windows.Forms.TreeView
    Friend WithEvents ImageList1 As System.Windows.Forms.ImageList
    Friend WithEvents Button1 As System.Windows.Forms.Button
    Friend WithEvents Button2 As System.Windows.Forms.Button
    <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
        Me.components = New System.ComponentModel.Container
        Dim resources As System.Resources.ResourceManager = New System.Resources.ResourceManager(GetType(Form2))
        Me.TreeView1 = New System.Windows.Forms.TreeView
        Me.ImageList1 = New System.Windows.Forms.ImageList(Me.components)
        Me.Button1 = New System.Windows.Forms.Button
        Me.Button2 = New System.Windows.Forms.Button
        Me.SuspendLayout()
        '
        'TreeView1
        '
        Me.TreeView1.ImageIndex = -1
        Me.TreeView1.Location = New System.Drawing.Point(8, 8)
        Me.TreeView1.Name = "TreeView1"
        Me.TreeView1.SelectedImageIndex = -1
        Me.TreeView1.Size = New System.Drawing.Size(208, 176)
        Me.TreeView1.TabIndex = 0
        '
        'ImageList1
        '
        Me.ImageList1.ImageSize = New System.Drawing.Size(16, 16)
        Me.ImageList1.ImageStream = CType(resources.GetObject("ImageList1.ImageStream"), System.Windows.Forms.ImageListStreamer)
        Me.ImageList1.TransparentColor = System.Drawing.Color.Transparent
        '
        'Button1
        '
        Me.Button1.Location = New System.Drawing.Point(224, 120)
        Me.Button1.Name = "Button1"
        Me.Button1.Size = New System.Drawing.Size(64, 32)
        Me.Button1.TabIndex = 1
        Me.Button1.Text = "Change Status"
        '
        'Button2
        '
        Me.Button2.Location = New System.Drawing.Point(224, 160)
        Me.Button2.Name = "Button2"
        Me.Button2.Size = New System.Drawing.Size(64, 32)
        Me.Button2.TabIndex = 1
        Me.Button2.Text = "Undo Change"
        '
        'Form2
        '
        Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13)
        Me.ClientSize = New System.Drawing.Size(292, 266)
        Me.Controls.Add(Me.Button1)
        Me.Controls.Add(Me.TreeView1)
        Me.Controls.Add(Me.Button2)
        Me.Name = "Form2"
        Me.Text = "Form2"
        Me.ResumeLayout(False)

    End Sub

#End Region
    Public tn1, tn2, tn3 As TreeNode
    Private Sub Form2_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Me.TreeView1.ImageList = Me.ImageList1

        tn1 = New TreeNode("C:\", 0, 0)
        tn2 = New TreeNode("Windows", 1, 1)
        tn3 = New TreeNode("Program Files", 2, 2)

        tn1.Nodes.Add(tn2)
        tn1.Nodes.Add(tn3)
        Me.TreeView1.Nodes.Add(tn1)

    End Sub


    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        tn1.ImageIndex = 1
        tn1.SelectedImageIndex = 1
    End Sub

    Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
        tn1.ImageIndex = 0
        tn1.SelectedImageIndex = 0
    End Sub
End Class
0
 
LVL 96

Expert Comment

by:Bob Learned
ID: 9877250
The normal behavior for the node is to have one image, and I can't think of another way around that limitation right now.
0
 
LVL 9

Author Comment

by:tinchos
ID: 9877313
malharone

I need to show both things... one possible suggestion is TheLearnedOne's that is to compose both images and show that ones, but I'm looking if there is a way to achieve it in a different way.


TheLearnedOne

I just think that Microsoft must have made it some way, and I was trying to achieve that. Besides, do you know any way of composing 2 images at runtime so as to say

Image image1 = nodeImage;
Image image2 = statusImage;

Image image3 = image1 + image2;        // it would be the composing of both images........ so as to avoid having all the combination of images?

Tincho
0
 
LVL 9

Expert Comment

by:malharone
ID: 9877343
do you have to combine the images at runtime?? can't you first create your image3 at design time -- using an image editor, and then use it? this may not be the best solution, but saves you render time at execution.
0
 
LVL 9

Author Comment

by:tinchos
ID: 9877402
Nop, its not viable

Imagine that you have 6 (A, B, C, D, E, F) different images for nodes and 6 possible states (1, 2, 3, 4, 5, 6)

then you would have 36 images in your imagelist
(A1, A2, A3, A4, A5, A6, B1, B2, B3, B4, B5, B6, C1, C2, C3, C4, C5, C6, D1, D2, D3, D4, D5, D6, E1, E2, E3, E4, E5, E6, F1, F2, F3, F4, F5, F6)

and the number of images and status can be higher, so it would end up with the image list being too big.

Tincho
0
 
LVL 9

Expert Comment

by:malharone
ID: 9877461
yup.. you could end up with
n! -- n factorial number of images.
let me check if you can programmatically "merge" two images. do they have the same dimension??
0
 
LVL 96

Expert Comment

by:Bob Learned
ID: 9877473
I know that you can use the Graphics object:  Graphics.DrawImage(image, x, y) to draw one image on another, but I wouldn't know what the C# syntax is.
0
Find Ransomware Secrets With All-Source Analysis

Ransomware has become a major concern for organizations; its prevalence has grown due to past successes achieved by threat actors. While each ransomware variant is different, we’ve seen some common tactics and trends used among the authors of the malware.

 
LVL 9

Author Comment

by:tinchos
ID: 9877491
malharone

yes, they do.....

TheLearnedOne

Graphics.DrawImage(image, x, y)
which one would be the first image and which one the second?

Tincho

0
 
LVL 96

Expert Comment

by:Bob Learned
ID: 9877492
BTW In the history of Micro$oft, there has been a lot of magic performed that they haven't let us "little people" in on.  There is a lot of talent in that company, so I would say that they just created a control that does just what they need, and it doesn't necessarily have to be a TreeView, it just has to look like one.  There is no way of telling what was done from the end result!
0
 
LVL 96

Expert Comment

by:Bob Learned
ID: 9877540
If we were going to use the SourceSafe functionality as a template:

Image #1:  Lock state, image #2 module type.

Get the graphics object for #1.  Make the image wider by the amount of #2.  

VB Code:
   Private Sub PictureBox1_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles PictureBox1.Paint

      Dim w As Integer = Me.PictureBox1.Width
      Me.PictureBox1.Size = New Size(w + Me.PictureBox2.Width, Me.PictureBox1.Height)

      Dim g As Graphics = e.Graphics

      g.DrawImage(Me.PictureBox2.Image, w, 0)

   End Sub
0
 
LVL 9

Expert Comment

by:malharone
ID: 9877996
assuming you have 3 differnt picture boxes on the form.

        Dim b1, b2 As Bitmap
        b1 = New Bitmap("C:\WINDOWS\Web\Wallpaper\Ripple.jpg")
        b2 = New Bitmap("C:\WINDOWS\Web\Wallpaper\Autumn.jpg")
        Me.PictureBox1.Image = b1
        Me.PictureBox2.Image = b2
        Dim b3 As New Bitmap(b1)
        Dim x, y As Integer
        x = Math.Min(b1.Width, b2.Width)
        y = Math.Min(b1.Height, b2.Height)
        Dim i, j As Integer
        For i = 1 To x Step 2
            For j = 1 To y Step 2
                b3.SetPixel(i, j, b2.GetPixel(i, j))
            Next
        Next
        Me.PictureBox3.Image = b3
0
 
LVL 9

Author Comment

by:tinchos
ID: 9878015
TheLearnedOne, malharone

Thanks for your posts........
I'm going home now, I'll try them tomorrow, but at least the idea seems to be that one.

Tincho
0
 
LVL 9

Expert Comment

by:malharone
ID: 9878036
fix:
change
        x = Math.Min(b1.Width, b2.Width)
        y = Math.Min(b1.Height, b2.Height)

to
        x = Math.Min(b1.Width, b2.Width) - 1
        y = Math.Min(b1.Height, b2.Height) - 1
0
 
LVL 9

Author Comment

by:tinchos
ID: 9882220
TheLearnedOne

I'm looking for a way to compose both images into one, not to paint them at the same time. Any ideas of how to do it?


malharone

I've looked at your code, and it seems that it's not composing both images but

newImage = image1
then overwrite each pixel in image1 with the pixel in image2

so, it's kind of overwriting newImage with image2 and there's nothing left from image1

Am I right?

Tincho
0
 
LVL 96

Expert Comment

by:Bob Learned
ID: 9882245
Sometimes we struggle to get on the same page.

Initially, when the program first runs, you can programmatically combine all images, as necessary.  You can use a picture box control to perform all the work.  Once all the images are constructed, they can be added to the ImageList control.

Painting, composing, are basically the same process.  All you need is to be able to have a picture box where the .Image property contains the graphics for both, whether you "compose" or "paint", they are persistent graphics, and you can add them to the ImageList.
0
 
LVL 9

Author Comment

by:tinchos
ID: 9882310
TheLearnedOne

I understood the first paragraph, but the socond one I'm not sure about what you meant.

My question was because your function was PictureBox1_Paint and I only have a graphic instance in the paint method.

Tincho
0
 
LVL 96

Accepted Solution

by:
Bob Learned earned 250 total points
ID: 9882706
Okay, now you see what I mean about being on the same page.  

You are right, the form would have to be visible before you get the Graphics.  Not a good option.

It took me a while, since I hadn't worked much with this, but I have learned something for myself.  I tried this in VB.NET for myself:

(1)  Defined module-level Bitmap and Graphics:  

      Dim workingBitmap As Bitmap
      Dim g As Graphics

(2)  Added three picture box controls:  pictureCombine (32 x 16), picture1 (16 x 16), and picture2 (16 x 16)

(3)  Created CreateImage routine:

   Private Sub CreateImage()

      workingBitmap = New Bitmap(Me.pictureCombine.Image, 32, 16)

      g = Graphics.FromImage(workingBitmap)

      g.Clear(Color.White)

      g.DrawImage(Me.picture1.Image, 0, 0)
      g.DrawImage(Me.picture2.Image, 16, 0)

      Me.pictureCombine.Image = workingBitmap

   End Sub

(4) Added this code to Form_Closing routine (If you dispose of this to early, you will get errors):

      workingBitmap.Dispose()
      g.Dispose()

What I got was two images combined onto one picture box (pictureCombine) that was 32 x 16.  You could add this image to the ImageList.  Also, the form wasn't visible, so this should be more what you would need.
0
 
LVL 9

Author Comment

by:tinchos
ID: 9883476
Thanks TheLearnedOne

I'm going home now, let me check it back on monday when I return to work and I'll let you know

Tincho
0
 
LVL 9

Author Comment

by:tinchos
ID: 9883491
Sorry, on tuesday (Monday is a holiday in Argentina)

0
 
LVL 9

Author Comment

by:tinchos
ID: 9942566
Sorry for the delay in the response TheLearnedOne

I've tested your code and it worked just fine.
Even though it was not the original solution I was looking for (I was looking for something already implemented in .net), it is a very useful and workable alternative.

Thanks a lot

Tincho
0
 
LVL 96

Expert Comment

by:Bob Learned
ID: 9942578
Your welcome.  I wish I could have provided you with a better solution, but I couldn't find one.
0
 
LVL 9

Author Comment

by:tinchos
ID: 9942611
No problem at all

As I said before, it was quite useful, and when solutions cannot be achieved, alternatives are as valid as them.

Tincho
0

Featured Post

IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

Join & Write a Comment

Extention Methods in C# 3.0 by Ivo Stoykov C# 3.0 offers extension methods. They allow extending existing classes without changing the class's source code or relying on inheritance. These are static methods invoked as instance method. This…
Calculating holidays and working days is a function that is often needed yet it is not one found within the Framework. This article presents one approach to building a working-day calculator for use in .NET.
Access reports are powerful and flexible. Learn how to create a query and then a grouped report using the wizard. Modify the report design after the wizard is done to make it look better. There will be another video to explain how to put the final p…
This video shows how to remove a single email address from the Outlook 2010 Auto Suggestion memory. NOTE: For Outlook 2016 and 2013 perform the exact same steps. Open a new email: Click the New email button in Outlook. Start typing the address: …

758 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

20 Experts available now in Live!

Get 1:1 Help Now