 |
|
 |
This code is very usefull for me. but still hve some issues.I have 2 treeviews, and i have to restrict some nodes being dragged. when i try
to drag and drop this restriced node to the same treeview its working fine(drag cancelled). But when i drop this restricted node to another treeview its getting copied and removing from first treeview. an anyone help me to restrict this node being dragged to any treeview.
anu&jiby
|
|
|
|
 |
|
 |
I might be too late, but you should have added the "block" condition on the second tree view as well.
|
|
|
|
 |
|
 |
As others have mentioned it is kind of buggy, the fact that it made my tree view smaller while I was dragging kinda turned me off. It also flickers alot.
AliR.
Visual C++ MVP
|
|
|
|
 |
|
 |
It was mentioned earlier, great article topic, because treeviews are such popular controls, but its flicker full and the auto resize doesnt work if you are dragging a node to the bottom, could have been a killer if some usability issues were covered.
|
|
|
|
 |
|
 |
Hello,
I am wondering if anyone would know how to drag and drop from one tree control to another tree control?
Thanks
|
|
|
|
 |
|
|
 |
|
 |
if the answere is yes, where can i download it?
if no, it give me this error:
Visual Studio cannot start debugging because the debug target 'C:\Program Files\Microsoft Visual Studio .NET 2003\Common7\IDE\devenv.exe' is
missing. Please build the project and retry, or set the OutputPath and AssemblyName properties appropriately to point at the correct location for the
target assembly.
Visual Studio cannot start debugging because the debug target 'C:\Program Files\Microsoft Visual Studio .NET 2003\Common7\IDE\devenv.exe' is
missing. Please build the project and retry, or set the OutputPath and AssemblyName properties appropriately to point at the correct location for the
target assembly.
|
|
|
|
 |
|
 |
You probably need to change the startup project. Right click on the "TestApp" project and select "Set as Startup Project"
|
|
|
|
 |
|
 |
I had quite a few problems with this code (some of which have already been reported) including:
-Treeview control itself resizing when dragging.
-Source node being deleted with copy operations.
-High flicker rate due to redrawing on small cursor movements.
-Events not firing (due to events in base class not being called).
-Target node still showing as selected after aborting a drag operation.
-Should be easier to control what type of nodes you can drag ONTO, not only which ones you can initiate dragging FROM.
-Cntrl/Shift/Alt + Drag not implemented
That said, I did still find it to be useful starting point.
|
|
|
|
 |
|
 |
Hi
I am trying to add nodes into the treeview by dragging items to the treeview. Could you please tell me how to do that?
Thanks!
Sebi
|
|
|
|
 |
|
 |
Hi,
I ran the test application and there is a problem with node highlighting: background color turn black and remain black. Maybe the code doesn't work anymore and needs to be updated?
Mathieu
|
|
|
|
 |
|
 |
Does anyone know why this occurs and how to make it stop?
|
|
|
|
 |
|
 |
It's because in the code the node is set to background color of "HighlightText" which on most systems is default. I believe this is a mistake and should be set to SystemColors.Window. At least that's what worked for me.
|
|
|
|
 |
|
 |
This is great, but what if you can drag the node, but need to cancel the drag according to the node you are trying to drop it on? Like a document, shouldnt become a child of another document. But when I try to do a DragDrop event to cancel it, it never gets called. Is there a fix I need to do to this control, or would you be able to post a fixed update that would allow this?
Thanks!!!!
invid
http://invid.funxion.net
|
|
|
|
 |
|
 |
hi, how can I drag data from other control to this treeview, It will not fire the dragcomplete event.
|
|
|
|
 |
|
 |
I have a number of nodes that I need to update as part of a process i.e. change the icon as each node task is completed. However when I use the node.EnsureVisible() method, if the node text is long and the scroll bars are visible it scrolls way over to the right, hiding the navigation lines/crosses - quite annoying.
I created a method "EnsureVisibleWithoutRightScrolling" that can be called instead of EnsureVisible() and added the following code to fix this:
// Sendmessage constants
private const int WM_HSCROLL = 276;
private const int SB_LEFT = 6;
[DllImport("user32.dll")]
private static extern int SendMessage(IntPtr hWnd, int wMsg, int wParam, int lParam);
public void EnsureVisibleWithoutRightScrolling(TreeNode node)
{
this.BeginUpdate();
// we do the standard call..
node.EnsureVisible();
// ..and afterwards we scroll to the left again!
SendMessage(this.Handle, WM_HSCROLL, SB_LEFT , 0);
this.EndUpdate();
}
Original article for EnsureVisibleWithoutRightScrolling is here:
http://www.codeproject.com/cs/miscctrl/NoScrollingTree.asp[^]
|
|
|
|
 |
|
 |
you can use the API function CreateIconIndirect to create any cursor from a bitmap. There is not size limit so you can draw the item into a bitmap and convert it into a cursor. The following class can be used for that. An instance of this class must exists as long as the cursor is displayed.
using System;
using System.Windows.Forms;
using System.Drawing;
using System.Runtime.InteropServices;
namespace aux
{
///
/// Creates a Cursor from any bitmap. You can use the alpha-channel
/// for transparency effects.
///
public class BitmapCursor : IDisposable
{
#region Win-API imports
///
/// API-Structure ICONINFO
///
///
[StructLayout(LayoutKind.Sequential)]
public struct ICONINFO
{
public bool fIcon;
public uint xHotspot;
public uint yHotspot;
public IntPtr hbmMask;
public IntPtr hbmColor;
}
///
/// API function CreateIconIndirect
///
[System.Runtime.InteropServices.DllImport("USER32.DLL")]
public static extern IntPtr CreateIconIndirect( ref ICONINFO iconinfo );
///
/// API function DestryIcon
///
[System.Runtime.InteropServices.DllImport("USER32.DLL")]
public static extern bool DestroyIcon( IntPtr hIcon );
#endregion
#region private
private ICONINFO iconInfo;
private Cursor cursor = null;
private IntPtr handle = IntPtr.Zero;
private void Create()
{
handle = CreateIconIndirect( ref iconInfo );
cursor = new Cursor( handle );
}
#endregion
#region constructors and destructor
public BitmapCursor( System.Drawing.Bitmap bmp, int HotSpotX, int HotSpotY )
{
iconInfo = new ICONINFO();
iconInfo.fIcon = false;
iconInfo.xHotspot = 0;
iconInfo.yHotspot = 0;
iconInfo.hbmMask = bmp.GetHbitmap();
iconInfo.hbmColor = bmp.GetHbitmap();
Create();
}
///
/// Creates a cursor from a bitmap and combines it with another cursor.
///
public BitmapCursor( System.Drawing.Bitmap bmp, Cursor Cursor )
{
iconInfo = new ICONINFO();
iconInfo.fIcon = false;
iconInfo.xHotspot = 0;
iconInfo.yHotspot = 0;
using( System.Drawing.Bitmap bmpdup = bmp.Clone() as System.Drawing.Bitmap )
{
using( Graphics g = Graphics.FromImage( bmpdup ) )
{
Cursor.Draw( g, new Rectangle( new Point( 0, 0 ), Cursor.Size ) );
}
iconInfo.hbmMask = bmpdup.GetHbitmap();
iconInfo.hbmColor = bmpdup.GetHbitmap();
Create();
}
}
///
/// destructor
///
~BitmapCursor()
{
Dispose( false );
}
#endregion
#region virtual methods
///
/// clean up resources
///
protected virtual void Dispose( bool disposing )
{
try
{
if( handle != IntPtr.Zero )
DestroyIcon( handle );
}
catch
{
}
}
#endregion
#region public properties
///
/// The Cursor-Object you can use
///
public Cursor Cursor
{
get
{
return cursor;
}
}
#endregion
#region IDisposable Member
///
/// free the used handles
///
public void Dispose()
{
GC.SuppressFinalize( this );
Dispose( true );
}
#endregion
}
}
Example for creating a drag cursor from a TreeNode that look like Windows-Explorer:
private BitmapCursor dragBitmapCursor = null;
protected virtual Cursor CreateDragCursor( TreeNode node )
{
int width = node.Bounds.Width;
int height = node.Bounds.Height;
Rectangle r = new Rectangle( 0, 0, width, height );
using( Graphics g0 = CreateGraphics() )
using( Bitmap bmp = new Bitmap( width, height * 4, g0 ) )
using( Graphics g = Graphics.FromImage( bmp ) )
{
g.Clear( Color.FromArgb( 0, 0, 0, 0 ) );
Color cb1 = Color.FromArgb( 255, 0, 89, 181 );
Color cb2 = Color.FromArgb( 0, 0, 89, 181 );
using( Brush b = new System.Drawing.Drawing2D.LinearGradientBrush( r, cb1, cb2, 0, false ) )
g.FillRectangle( b, 0, 0, width, height );
Color ct1 = Color.FromArgb( 255, 255, 255, 255 );
Color ct2 = Color.FromArgb( 64, 255, 255, 255 );
using( Brush b = new System.Drawing.Drawing2D.LinearGradientBrush( r, ct1, ct2, 0, false ) )
g.DrawString( node.Text, Font, b, 0, 0 );
DragBitmapCursor = new BitmapCursor( bmp, Cursors.Default );
return DragBitmapCursor.Cursor;
}
}
|
|
|
|
 |
|
 |
CreateDragCursor: creates Cursor with expanded Subnodes...
Public Class BitmapCursor
Implements IDisposable
#Region "variables"
Private icon_Info As ICONINFO
Private cursor_ As System.Windows.Forms.Cursor = Nothing
Private handle As IntPtr = IntPtr.Zero
#End Region
#Region "constants"
Private Shared ReadOnly TreeviewOffset As System.Drawing.Point = New System.Drawing.Point(-1, 2)
Private Const Alpha As Double = 0.33
#End Region
_
Private Structure ICONINFO
Public fIcon As Boolean
Public xHotspot As System.UInt32
Public yHotspot As System.UInt32
Public hbmMask As IntPtr
Public hbmColor As IntPtr
End Structure
_
Private Shared Function CreateIconIndirect(ByRef iconinfo As ICONINFO) As IntPtr
End Function
_
private Shared Function DestroyIcon(ByVal hIcon As IntPtr) As Boolean
End Function
Private Sub Create()
handle = CreateIconIndirect(icon_Info)
cursor_ = New Cursor(handle)
End Sub
Private Sub New(ByVal bmp As System.Drawing.Bitmap, ByVal HotSpotX As Integer, ByVal HotSpotY As Integer)
icon_Info = New ICONINFO()
icon_Info.fIcon = False
icon_Info.xHotspot = 0
icon_Info.yHotspot = 0
icon_Info.hbmMask = bmp.GetHbitmap()
icon_Info.hbmColor = bmp.GetHbitmap()
Create()
End Sub
' ' Creates a cursor from a bitmap and combines it with another cursor.
'
Private Sub New(ByVal bmp As System.Drawing.Bitmap, ByVal CursorToCombine As System.Windows.Forms.Cursor)
icon_Info = New ICONINFO()
icon_Info.fIcon = False
icon_Info.xHotspot = 0
icon_Info.yHotspot = 0
Using bmpdup As System.Drawing.Bitmap = CType(bmp.Clone(), System.Drawing.Bitmap)
Using g As Graphics = System.Drawing.Graphics.FromImage(bmpdup)
CursorToCombine.Draw(g, New System.Drawing.Rectangle(New Point(0, 0), CursorToCombine.Size))
End Using
icon_Info.hbmMask = bmpdup.GetHbitmap()
icon_Info.hbmColor = bmpdup.GetHbitmap()
Create()
End Using
End Sub
Private ReadOnly Property Cursor() As System.Windows.Forms.Cursor
Get
Return Me.cursor_
End Get
End Property
Public Shared Function CreateDragCursor(ByRef NodeToDraw As System.Windows.Forms.TreeNode, ByRef CursorToCombine As System.Windows.Forms.Cursor) As Cursor
If Not NodeToDraw Is Nothing Then
Dim NodesBounds As System.Drawing.Rectangle = GetNodesBounds(NodeToDraw)
Dim ControlScreenshot As System.Drawing.Bitmap = New System.Drawing.Bitmap(NodeToDraw.TreeView.Width, NodeToDraw.TreeView.Height)
Dim CursorBitmap As System.Drawing.Bitmap = New System.Drawing.Bitmap(Math.Max(NodesBounds.Width, CursorToCombine.Size.Width), Math.Max(NodesBounds.Height, CursorToCombine.Size.Height))
Dim CursorBitmapRectangle As System.Drawing.Rectangle = New System.Drawing.Rectangle(0, 0, NodesBounds.Width, NodesBounds.Height)
NodeToDraw.TreeView.DrawToBitmap(ControlScreenshot, New System.Drawing.Rectangle(0, 0, ControlScreenshot.Width, ControlScreenshot.Height))
Using g As Graphics = Graphics.FromImage(CursorBitmap)
g.Clear(NodeToDraw.TreeView.BackColor)
g.DrawImage(ControlScreenshot, CursorBitmapRectangle, NodesBounds, GraphicsUnit.Pixel)
End Using
Call AdjustAlpha(CursorBitmap, Alpha, NodeToDraw.TreeView.BackColor)
Return New BitmapCursor(CursorBitmap, CursorToCombine).Cursor
Else
Return CursorToCombine
End If
End Function
Private Shared Function GetNodeBounds(ByRef NodeToDraw As System.Windows.Forms.TreeNode) As System.Drawing.Rectangle
If Not NodeToDraw Is Nothing Then
Try
Return New Rectangle(NodeToDraw.Bounds.Left - NodeToDraw.TreeView.ImageList.ImageSize.Width + TreeviewOffset.X, NodeToDraw.Bounds.Top + TreeviewOffset.Y, NodeToDraw.Bounds.Width + NodeToDraw.TreeView.ImageList.ImageSize.Width, NodeToDraw.Bounds.Height)
Catch ex As Exception
Return New Rectangle(NodeToDraw.Bounds.Left - 1, NodeToDraw.Bounds.Top + 2, NodeToDraw.Bounds.Width, NodeToDraw.Bounds.Height)
End Try
Else
Return System.Drawing.Rectangle.Empty
End If
End Function
Private Shared Function GetNodesBounds(ByRef NodeToDraw As System.Windows.Forms.TreeNode) As System.Drawing.Rectangle
Dim ChildNode As System.Windows.Forms.TreeNode
Dim Result As System.Drawing.Rectangle
If Not NodeToDraw Is Nothing Then
Result = GetNodeBounds(NodeToDraw)
If NodeToDraw.IsExpanded AndAlso NodeToDraw.Nodes.Count > 0 Then
If NodeToDraw.Nodes.Count > 0 Then
For Each ChildNode In NodeToDraw.Nodes
Result = System.Drawing.Rectangle.Union(Result, GetNodesBounds(ChildNode))
Next ChildNode
End If
End If
Return Result
Else
Return System.Drawing.Rectangle.Empty
End If
End Function
^
private Sub AdjustAlpha(ByRef ImageToAdjust As System.Drawing.Bitmap, ByVal Alpha As Double, ByRef TransparencyColor As System.Drawing.Color)
Dim ActColor As System.Drawing.Color
Dim x, y As Integer
Dim AlphaByte As Integer = CInt(Math.Round(Alpha * 255))
For x = 0 To ImageToAdjust.Width - 1 Step 1
For y = 0 To ImageToAdjust.Height - 1 Step 1
ActColor = ImageToAdjust.GetPixel(x, y)
If ActColor.R = TransparencyColor.R AndAlso _
ActColor.G = TransparencyColor.G AndAlso _
ActColor.B = TransparencyColor.B Then
ImageToAdjust.SetPixel(x, y, Color.FromArgb(0, ActColor))
Else
ImageToAdjust.SetPixel(x, y, Color.FromArgb(AlphaByte, ActColor))
End If
Next y
Next x
End Sub
Protected Overrides Sub Finalize()
Dispose(False)
End Sub
Private Sub Dispose() Implements IDisposable.Dispose
GC.SuppressFinalize(Me)
Dispose(True)
End Sub
Private Sub Dispose(ByVal disposing As Boolean)
Try
If Not handle = IntPtr.Zero Then
DestroyIcon(handle)
End If
Catch ex As Exception
End Try
End Sub
End Class
|
|
|
|
 |
|
 |
In my app I wanted to make the icon jump a certain amount of pixels instead of following the mouse pointer px per px.
So i have implemented an onMouseMove event which has to change the hotspot of the cursor continiously. Therefore everytime a new cursor has to be created.
After a few hundred times you'll get an numericargumentexception from the win32 api.
solution: you have to destroy the current handle with "DestroyIcon" before creating a new one.
also constructor with hotspot was not setting the hotspot
Here the new class with my updates and changes to my needs.
This was a great help for me, as suprisinly, there's not alot to find on the topic.
using System;
using System.Windows.Forms;
using System.Drawing;
using System.Runtime.InteropServices;
namespace PerdumImageEditor._Klassen
{
///
/// Creates a Cursor from any bitmap. You can use the alpha-channel
/// for transparency effects.
///
/// you can use the API function CreateIconIndirect to create any cursor from a bitmap.
/// There is not size limit so you can draw the item into a bitmap and convert it into a cursor.
/// The following class can be used for that. An instance of this class must exists as long as the cursor is displayed.
///
public class clsBitmapCursor : IDisposable
{
#region Win-API imports
///
/// API-Structure ICONINFO
///
///
[StructLayout(LayoutKind.Sequential)]
public struct ICONINFO
{
public bool fIcon;
public uint xHotspot;
public uint yHotspot;
public IntPtr hbmMask;
public IntPtr hbmColor;
}
///
/// API function CreateIconIndirect
///
[System.Runtime.InteropServices.DllImport("USER32.DLL")]
public static extern IntPtr CreateIconIndirect( ref ICONINFO iconinfo );
///
/// API function DestryIcon
///
[System.Runtime.InteropServices.DllImport("USER32.DLL")]
public static extern bool DestroyIcon( IntPtr hIcon );
#endregion
private ICONINFO iconInfo;
private Cursor cursor = null;
private IntPtr handle = IntPtr.Zero;
#region constructors and destructor
public clsBitmapCursor(System.Drawing.Bitmap bmp)
{
iconInfo = new ICONINFO();
iconInfo.fIcon = false;
iconInfo.xHotspot = 0;
iconInfo.yHotspot = 0;
iconInfo.hbmMask = bmp.GetHbitmap();
iconInfo.hbmColor = bmp.GetHbitmap();
Create();
}
public clsBitmapCursor( System.Drawing.Bitmap bmp, uint HotSpotX, uint HotSpotY )
{
iconInfo = new ICONINFO();
iconInfo.fIcon = false;
iconInfo.xHotspot = HotSpotX;
iconInfo.yHotspot = HotSpotY;
iconInfo.hbmMask = bmp.GetHbitmap();
iconInfo.hbmColor = bmp.GetHbitmap();
Create();
}
///
/// destructor
///
~clsBitmapCursor()
{
Dispose( false );
}
#endregion
///
/// clean up resources
///
protected virtual void Dispose( bool disposing )
{
try
{
if( handle != IntPtr.Zero )
DestroyIcon( handle );
}
catch
{
}
}
public void moveHotspot(int x, int y)
{
iconInfo.xHotspot = (uint)x;
iconInfo.yHotspot = (uint)y;
Create();
}
private void Create()
{
if (handle != null) DestroyIcon(handle);
handle = CreateIconIndirect(ref iconInfo);
cursor = new Cursor(handle);
}
///
/// The Cursor-Object you can use
///
public Cursor Cursor
{
get
{
return cursor;
}
}
///
/// free the used handles
///
public void Dispose()
{
GC.SuppressFinalize( this );
Dispose( true );
}
}
}
|
|
|
|
 |
|
 |
I have two types of nodes in my treeview, regular nodes and 'myTreeNodes' which just contain some extra information (such as an Image object). I noticed that if i move one regular node into another regular node, all the 'myTreeNodes' in the node i just moved get messed up, losing all the values for their custom fields.
i traced this to the Clone method you suggested using when copying the nodes.
This is the fix i propose, it works well:
In the DragDrop method:
dragNode.Remove();
targetNode.Nodes.Insert(0, dragNode);
targetNode.Expand();
you don't need to clone it, because removing it only takes it out of its parent nodelist, as long as you maintain a reference to the object, you maintain all the data in the object. I used Insert because i was short on time and i used Insert for node-swapping in my treeview, add should work just as well.
by the way, thanks for your code, it was very helpful
|
|
|
|
 |
|
 |
Hi,
Thanx for this control. It saves me a lot of time. The OnDragLeave event does not set the previous node to the 'not selected' color. This means that whenever you leave the control while dragging something the previous node stays 'selected'. Your whole tree can appear selected after a while.
I made this code change:
if ( this._previousNode != null )
{
this._previousNode.BackColor = SystemColors.HighlightText;
this._previousNode.ForeColor = SystemColors.ControlText;
}
Cheers
|
|
|
|
 |
|
 |
actually the problem is that the node is never ACTUALLY selected.
instead of tracking the previous and next node, and then setting the colors, why don't you just do
this.selectedNode = targetNode (or something to that extent.. i don't have the code up right now)
but anyway, yes... treeviews have a property for the selected node, just set that property to the node that is at the current point.
[note: i'm on .net 2.0 beta 2 right now, so you may not have that]
|
|
|
|
 |
|
 |
Hi smallguy78!
when I wrote my node named MyNode extend TreeNode, ur control didnt work???
Can u show me how to correct it?
Thanks
|
|
|
|
 |
|
|
 |
|
 |
Hi!!!
Can I do this functionality with Vb.net ?
Michel
|
|
|
|
 |