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
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
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.
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
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.
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
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)
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)
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
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.ICon tainer
'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.TreeV iew
Friend WithEvents ImageList1 As System.Windows.Forms.Image List
Friend WithEvents Button1 As System.Windows.Forms.Butto n
Friend WithEvents Button2 As System.Windows.Forms.Butto n
<System.Diagnostics.Debugg erStepThro ugh()> Private Sub InitializeComponent()
Me.components = New System.ComponentModel.Cont ainer
Dim resources As System.Resources.ResourceM anager = New System.Resources.ResourceM anager(Get Type(Form2 ))
Me.TreeView1 = New System.Windows.Forms.TreeV iew
Me.ImageList1 = New System.Windows.Forms.Image List(Me.co mponents)
Me.Button1 = New System.Windows.Forms.Butto n
Me.Button2 = New System.Windows.Forms.Butto n
Me.SuspendLayout()
'
'TreeView1
'
Me.TreeView1.ImageIndex = -1
Me.TreeView1.Location = New System.Drawing.Point(8, 8)
Me.TreeView1.Name = "TreeView1"
Me.TreeView1.SelectedImage Index = -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( "ImageList 1.ImageStr eam"), System.Windows.Forms.Image ListStream er)
Me.ImageList1.TransparentC olor = System.Drawing.Color.Trans parent
'
'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.TreeVie w1)
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
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.ICon
'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.TreeV
Friend WithEvents ImageList1 As System.Windows.Forms.Image
Friend WithEvents Button1 As System.Windows.Forms.Butto
Friend WithEvents Button2 As System.Windows.Forms.Butto
<System.Diagnostics.Debugg
Me.components = New System.ComponentModel.Cont
Dim resources As System.Resources.ResourceM
Me.TreeView1 = New System.Windows.Forms.TreeV
Me.ImageList1 = New System.Windows.Forms.Image
Me.Button1 = New System.Windows.Forms.Butto
Me.Button2 = New System.Windows.Forms.Butto
Me.SuspendLayout()
'
'TreeView1
'
Me.TreeView1.ImageIndex = -1
Me.TreeView1.Location = New System.Drawing.Point(8, 8)
Me.TreeView1.Name = "TreeView1"
Me.TreeView1.SelectedImage
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(
Me.ImageList1.TransparentC
'
'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.TreeVie
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.
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
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.
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
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??
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.
ASKER
malharone
yes, they do.....
TheLearnedOne
Graphics.DrawImage(image, x, y)
which one would be the first image and which one the second?
Tincho
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.Paint EventArgs) 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
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.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
End Sub
assuming you have 3 differnt picture boxes on the form.
Dim b1, b2 As Bitmap
b1 = New Bitmap("C:\WINDOWS\Web\Wal lpaper\Rip ple.jpg")
b2 = New Bitmap("C:\WINDOWS\Web\Wal lpaper\Aut umn.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
Dim b1, b2 As Bitmap
b1 = New Bitmap("C:\WINDOWS\Web\Wal
b2 = New Bitmap("C:\WINDOWS\Web\Wal
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
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
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
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
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
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.
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.
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
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
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
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
I'm going home now, let me check it back on monday when I return to work and I'll let you know
Tincho
ASKER
Sorry, on tuesday (Monday is a holiday in Argentina)
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
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.
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
As I said before, it was quite useful, and when solutions cannot be achieved, alternatives are as valid as them.
Tincho
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.ICon
'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.TreeV
Friend WithEvents ImageList1 As System.Windows.Forms.Image
<System.Diagnostics.Debugg
Me.components = New System.ComponentModel.Cont
Dim resources As System.Resources.ResourceM
Me.TreeView1 = New System.Windows.Forms.TreeV
Me.ImageList1 = New System.Windows.Forms.Image
Me.SuspendLayout()
'
'TreeView1
'
Me.TreeView1.ImageIndex = -1
Me.TreeView1.Location = New System.Drawing.Point(8, 8)
Me.TreeView1.Name = "TreeView1"
Me.TreeView1.SelectedImage
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(
Me.ImageList1.TransparentC
'
'Form2
'
Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13)
Me.ClientSize = New System.Drawing.Size(292, 266)
Me.Controls.Add(Me.TreeVie
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