Showing two images on a treenode

G

gooseneckster

Hi,

Does anyone have an idea on how to display two images on a treeview's
treenode? (.Net v1.1)

At the moment I have made a TreeViewEx component that inherits from
TreeView.
I'm overriding the OnPaint and there I call method below with
PaintEventArgs.Graphics and my root TreeNode:

private void SetImagePositions(Graphics g, TreeNode node)
{
if (node.IsVisible)
{
node.ImageIndex = 0; // for test, assumes an ImageList with two
images is chosen for the treeview
node.SelectedImageIndex = 0;
PictureBox statusImage = new PictureBox();
statusImage.Image = ImageList.Images[1]; // for test, assumes an
ImageList with two images is chosen for the treeview
statusImage.Location = new Point(node.Bounds.Left-22,
node.Bounds.Top);
statusImage.Size = new Size(16, 16);
g.DrawImage(statusImage.Image, statusImage.Location);

foreach(TreeNode childNode in node.Nodes)
SetImagePositions(g, childNode);
}
}

This however works badly, as if this triggers some other event which
makes the treeview redraw some of it's nodes again on top of the extra
image...

Does anyone have any idea, please help...

Thanks alot in advance,
Cheers
Jag
 
B

Bob Powell [MVP]

The tree control is a Windows Common Control and supports the notify custom
draw scheme. Unfortunately none of the Windows Forms wrapper exposes this
functionality but it can be done by overriding WndProc in the tree control
and providing the correct handlers for the various messages.

I have made extensively customized ListView objects that support full custom
drawing using these methods. I have nopt done a treeview as yet but the
principles are similar if not identical.

--
Bob Powell [MVP]
Visual C#, System.Drawing

Ramuseco Limited .NET consulting
http://www.ramuseco.com

Find great Windows Forms articles in Windows Forms Tips and Tricks
http://www.bobpowell.net/tipstricks.htm

Answer those GDI+ questions with the GDI+ FAQ
http://www.bobpowell.net/faqmain.htm

All new articles provide code in C# and VB.NET.
Subscribe to the RSS feeds provided and never miss a new article.
 
C

Claes Bergefall

You can use a state image as the second image (I assume you use the normal
ImageIndex for the first one). Unfortunately 1.1 doesn't expose any
properties to handle state images but some P/Invoke stuff will handle that
problem. Also note that this method won't work if you're using checkboxes in
your treeview. Here's some code that should help. It's in VB though so
you'll have to translate it

<StructLayout(LayoutKind.Sequential)> Friend Structure TVITEM
Friend mask As Integer
Friend hItem As IntPtr
Friend state As Integer
Friend stateMask As Integer
<MarshalAs(UnmanagedType.LPTStr)> Friend lpszText As String
Friend cchTextMax As Integer
Friend iImage As Integer
Friend iSelectedImage As Integer
Friend cChildren As Integer
Friend lParam As IntPtr
End Structure

Friend Const TVIF_STATE As Integer = &H8
Friend Const TVIS_STATEIMAGEMASK As Integer = &HF000
Friend Const TVSIL_STATE As Integer = 2

Friend Const TV_FIRST As Integer = &H1100
Friend Const TVM_SETITEMA As Integer = TV_FIRST + 13
Friend Const TVM_SETITEMW As Integer = TV_FIRST + 63
Friend Const TVM_SETIMAGELIST As Integer = TV_FIRST + 9

Friend Overloads Declare Auto Function SendMessage Lib "User32.dll" (ByVal
hwnd As IntPtr, ByVal msg As Integer, ByVal wParam As IntPtr, ByRef lParam
As TVITEM) As Integer
Friend Overloads Declare Auto Function SendMessage Lib "User32.dll" (ByVal
hwnd As IntPtr, ByVal msg As Integer, ByVal wParam As IntPtr, ByVal lParam
As IntPtr) As Integer

Friend Shared Function INDEXTOSTATEIMAGEMASK(ByVal i As Integer) As Integer
Return (i << 12)
End Function

Friend Shared Sub TreeView_SetStateImageIndex(ByVal hwnd As IntPtr, ByVal
hItem As IntPtr, ByVal imageIndex As Integer)
Dim tvi As TVITEM
tvi.hItem = hItem
tvi.mask = TVIF_STATE
tvi.stateMask = TVIS_STATEIMAGEMASK
tvi.state = INDEXTOSTATEIMAGEMASK(imageIndex)
If (Marshal.DefaultCharSize = 1) Then
SendMessage(hwnd, TVM_SETITEMA, IntPtr.Zero, tvi)
Else
SendMessage(hwnd, TVM_SETITEMW, IntPtr.Zero, tvi)
End If
End Sub

Friend Shared Sub TreeView_SetStateImageList(ByVal hwnd As IntPtr, ByVal
hImageList As IntPtr)
SendMessage(hwnd, TVM_SETIMAGELIST , New IntPtr(TVSIL_STATE),
hImageList)
End Sub

Use like this:

Create an ImageList containing the images you want (you can use the same as
for your normal images) and then call TreeView_SetStateImageList like this:
TreeView_SetStateImageList(yourTreeView.Handle, yourImageList.Handle)
(You only need to call it once)

Once you've done that you can call TreeView_SetStateImageIndex when you want
to set the image to display for a TreeNode:
TreeView_SetStateImageIndex(yourTreeView.Handle, yourTreeNode.Handle,
yourIndex)


/claes



Hi,

Does anyone have an idea on how to display two images on a treeview's
treenode? (.Net v1.1)

At the moment I have made a TreeViewEx component that inherits from
TreeView.
I'm overriding the OnPaint and there I call method below with
PaintEventArgs.Graphics and my root TreeNode:

private void SetImagePositions(Graphics g, TreeNode node)
{
if (node.IsVisible)
{
node.ImageIndex = 0; // for test, assumes an ImageList with two
images is chosen for the treeview
node.SelectedImageIndex = 0;
PictureBox statusImage = new PictureBox();
statusImage.Image = ImageList.Images[1]; // for test, assumes an
ImageList with two images is chosen for the treeview
statusImage.Location = new Point(node.Bounds.Left-22,
node.Bounds.Top);
statusImage.Size = new Size(16, 16);
g.DrawImage(statusImage.Image, statusImage.Location);

foreach(TreeNode childNode in node.Nodes)
SetImagePositions(g, childNode);
}
}

This however works badly, as if this triggers some other event which
makes the treeview redraw some of it's nodes again on top of the extra
image...

Does anyone have any idea, please help...

Thanks alot in advance,
Cheers
Jag
 
B

beniamino

Bob,

I went to your site to read up on some of your work regarding listview
to learn about the WndProc drawing. But I was not able to find any
related material. Would be able to point me in the direction of more
information?

Thanks,
Ben
The tree control is a Windows Common Control and supports the notify custom
draw scheme. Unfortunately none of the Windows Forms wrapper exposes this
functionality but it can be done by overriding WndProc in the tree control
and providing the correct handlers for the various messages.

I have made extensively customized ListView objects that support full custom
drawing using these methods. I have nopt done a treeview as yet but the
principles are similar if not identical.

--
Bob Powell [MVP]
Visual C#, System.Drawing

Ramuseco Limited .NET consulting
http://www.ramuseco.com

Find great Windows Forms articles in Windows Forms Tips and Tricks
http://www.bobpowell.net/tipstricks.htm

Answer those GDI+ questions with the GDI+ FAQ
http://www.bobpowell.net/faqmain.htm

All new articles provide code in C# and VB.NET.
Subscribe to the RSS feeds provided and never miss a new article.



Hi,

Does anyone have an idea on how to display two images on a treeview's
treenode? (.Net v1.1)

At the moment I have made a TreeViewEx component that inherits from
TreeView.
I'm overriding the OnPaint and there I call method below with
PaintEventArgs.Graphics and my root TreeNode:

private void SetImagePositions(Graphics g, TreeNode node)
{
if (node.IsVisible)
{
node.ImageIndex = 0; // for test, assumes an ImageList with two
images is chosen for the treeview
node.SelectedImageIndex = 0;
PictureBox statusImage = new PictureBox();
statusImage.Image = ImageList.Images[1]; // for test, assumes an
ImageList with two images is chosen for the treeview
statusImage.Location = new Point(node.Bounds.Left-22,
node.Bounds.Top);
statusImage.Size = new Size(16, 16);
g.DrawImage(statusImage.Image, statusImage.Location);

foreach(TreeNode childNode in node.Nodes)
SetImagePositions(g, childNode);
}
}

This however works badly, as if this triggers some other event which
makes the treeview redraw some of it's nodes again on top of the extra
image...

Does anyone have any idea, please help...

Thanks alot in advance,
Cheers
Jag
 
Top