Link to home
Start Free TrialLog in
Avatar of tinchos
tinchos

asked on

Images in a TreeView

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
Avatar of malharone
malharone

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
Avatar of Bob Learned
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.
Avatar of tinchos

ASKER

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
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.
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.
Avatar of tinchos

ASKER

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
"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)
Avatar of tinchos

ASKER

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
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
The normal behavior for the node is to have one image, and I can't think of another way around that limitation right now.
Avatar of tinchos

ASKER

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
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.
Avatar of tinchos

ASKER

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
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??
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.
Avatar of tinchos

ASKER

malharone

yes, they do.....

TheLearnedOne

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

Tincho

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!
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
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
Avatar of tinchos

ASKER

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
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
Avatar of tinchos

ASKER

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
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.
Avatar of tinchos

ASKER

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
ASKER CERTIFIED SOLUTION
Avatar of Bob Learned
Bob Learned
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of tinchos

ASKER

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
Avatar of tinchos

ASKER

Sorry, on tuesday (Monday is a holiday in Argentina)

Avatar of tinchos

ASKER

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
Your welcome.  I wish I could have provided you with a better solution, but I couldn't find one.
Avatar of tinchos

ASKER

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