Down and dirty KryptonTreeView

Share your code snippets, controls and screenshots.

Moderators: Phil Wright, Chris Porter

Down and dirty KryptonTreeView

Postby Nick71 » Mon Feb 21, 2011 10:05 pm

I needed a treeview control, and wanted it to fit in with the Krypton styles. I has a look at Angels extender toolkit, great stuff, but I didn't really want to distribute someone elses assembly without the source or a support contract, so was on my own. Below are a couple of screenshots...

Image Image

I've only really implemented what I needed, so hot tracking is not properly stylized, the Office 2007 palettes don't render great as they don't implement the glass effect amongst many other shortcomings, but it's a passable implementation for my requirements. I didn't bother finding out how to change the border, just used a KryptonTextBox behind my treeview and set my treeview with no border to get the same effect, maybe someone knows how this could be improved. Thought I'd share it, so if anyone wants to use it and makes any improvements we can all benefit. Phil, if you have any quick guides to improve it, much appreciated.

VB version...
Code: Select all
Imports ComponentFactory.Krypton.Toolkit
Imports System.Drawing
Imports System.Drawing.Drawing2D

Public Class KryptonTreeView
  Inherits TreeView

  Dim p_Manager As KryptonManager

  Public Sub New()
    FormatControl()

    ' Configure the TreeView control for owner-draw.
    Me.DrawMode = TreeViewDrawMode.OwnerDrawText

  End Sub

  Public Property Manager() As KryptonManager
    Get
      If p_Manager Is Nothing Then
        Try
          Dim Form As Form = Me.FindForm
          For Each Control In Me.FindForm.Controls
            If Control.GetType Is GetType(KryptonManager) Then
              p_Manager = Control
            End If
          Next
        Catch ex As Exception
        End Try
      End If
      Return p_Manager
    End Get
    Set(ByVal value As KryptonManager)
      p_Manager = value
    End Set
  End Property

  Private Sub FormatControl()
    Me.Font = KryptonManager.CurrentGlobalPalette.GetContentLongTextFont(PaletteContentStyle.ButtonStandalone, PaletteState.ContextNormal)
  End Sub

  ' Draws a node.
  Private Sub Me_DrawNode(ByVal sender As Object, ByVal e As DrawTreeNodeEventArgs) Handles Me.DrawNode

    e.DrawDefault = False

    ' Retrieve the node font. If the node font has not been set,
    ' use the TreeView font.
    Dim nodeFont As Font = e.Node.NodeFont
    If nodeFont Is Nothing Then
      nodeFont = CType(sender, TreeView).Font
    End If

    ' Draw the background and node text for a selected node.
    If e.Node Is MyBase.SelectedNode Then  '(e.State And TreeNodeStates.Selected) <> 0 Then

      ' Draw the background of the selected node. The NodeBounds
      ' method makes the highlight rectangle large enough to
      ' include the text of a node tag, if one is present.
      Dim HighlightGradientColor1 As System.Drawing.Color = Manager.GlobalPalette.GetBackColor1(PaletteBorderStyle.ButtonListItem, PaletteState.CheckedTracking)
      Dim HighlightGradientColor2 As System.Drawing.Color = Manager.GlobalPalette.GetBackColor2(PaletteBorderStyle.ButtonListItem, PaletteState.CheckedTracking)
      'Dim linGrBrush As New System.Drawing.Drawing2D.LinearGradientBrush(NodeBounds(e.Node), HighlightGradientColor1, HighlightGradientColor2, Drawing2D.LinearGradientMode.Vertical)

      'e.Graphics.FillRectangle(linGrBrush, NodeBounds(e.Node))

      DrawBlendGradient(e.Graphics, NodeBounds(e.Node), HighlightGradientColor1, HighlightGradientColor1, HighlightGradientColor2, 90)

      ' Draw the node text.
      Dim textBrush As New SolidBrush(KryptonManager.CurrentGlobalPalette.GetContentLongTextColor1(PaletteContentStyle.ButtonListItem, PaletteState.CheckedNormal))
      e.Graphics.DrawString(e.Node.Text, nodeFont, textBrush, e.Bounds.Left, e.Bounds.Top)

      ' Draw the focus rectangle large, making
      ' it large enough to include the text of the node tag, if present.
      Dim focusPen As New Pen(Manager.GlobalPalette.GetBorderColor1(PaletteBorderStyle.ButtonListItem, PaletteState.CheckedNormal))
      Try
        focusPen.Width = 1
        Dim focusBounds As New Rectangle(e.Node.Bounds.X, e.Node.Bounds.Y + 1, e.Node.Bounds.Width, e.Node.Bounds.Height - 2)
        DrawRoundedRectangle(e.Graphics, focusBounds, KryptonManager.CurrentGlobalPalette.GetBorderRounding(PaletteBorderStyle.ButtonListItem, PaletteState.CheckedNormal), focusPen)
      Finally
        focusPen.Dispose()
      End Try

    Else
      ' Draw the node text.
      Dim textBrush As New SolidBrush(KryptonManager.CurrentGlobalPalette.GetContentLongTextColor1(PaletteContentStyle.ButtonListItem, PaletteState.Normal))
      e.Graphics.DrawString(e.Node.Text, nodeFont, textBrush, e.Bounds.Left, e.Bounds.Top)
    End If

  End Sub 'Me_DrawNode

  Public Sub DrawRoundedRectangle(ByVal objGraphics As Graphics, _
                                  ByVal rect As Rectangle, _
                                  ByVal m_diameter As Integer, _
                                  ByVal Pen As Pen)
    If m_diameter = 0 Then
      objGraphics.DrawRectangle(Pen, rect)
      Exit Sub
    End If

    Dim m_intxAxis As Integer = rect.X
    Dim m_intyAxis As Integer = rect.Y
    Dim m_intWidth As Integer = rect.Width
    Dim m_intHeight As Integer = rect.Height

    'Dim g As Graphics
    Dim BaseRect As New RectangleF(m_intxAxis, m_intyAxis, m_intWidth, m_intHeight)
    Dim ArcRect As New RectangleF(BaseRect.Location, New SizeF(m_diameter, m_diameter))
    'top left Arc
    objGraphics.DrawArc(Pen, ArcRect, 180, 90)
    objGraphics.DrawLine(Pen, m_intxAxis + CInt(m_diameter / 2), m_intyAxis, m_intxAxis + m_intWidth - CInt(m_diameter / 2), m_intyAxis)

    ' top right arc
    ArcRect.X = BaseRect.Right - m_diameter
    objGraphics.DrawArc(Pen, ArcRect, 270, 90)
    objGraphics.DrawLine(Pen, m_intxAxis + m_intWidth, m_intyAxis + CInt(m_diameter / 2), m_intxAxis + m_intWidth, m_intyAxis + m_intHeight - CInt(m_diameter / 2))

    ' bottom right arc
    ArcRect.Y = BaseRect.Bottom - m_diameter
    objGraphics.DrawArc(Pen, ArcRect, 0, 90)
    objGraphics.DrawLine(Pen, m_intxAxis + CInt(m_diameter / 2), m_intyAxis + m_intHeight, m_intxAxis + m_intWidth - CInt(m_diameter / 2), m_intyAxis + m_intHeight)

    ' bottom left arc
    ArcRect.X = BaseRect.Left
    objGraphics.DrawArc(Pen, ArcRect, 90, 90)
    objGraphics.DrawLine(Pen, m_intxAxis, m_intyAxis + CInt(m_diameter / 2), m_intxAxis, m_intyAxis + m_intHeight - CInt(m_diameter / 2))

  End Sub

  Public Shared Sub DrawBlendGradient(ByVal g As Graphics, ByVal rect As Rectangle, ByVal LightColor As Color, ByVal DarkColor As Color, ByVal MiddleColor As Color, ByVal Angle As Single)
    Dim blend As New ColorBlend(4)

    blend.Positions(0) = 0.0F
    blend.Colors(0) = LightColor

    blend.Positions(1) = 0.8F
    blend.Colors(1) = DarkColor

    blend.Positions(2) = 0.8F
    blend.Colors(2) = DarkColor

    blend.Positions(3) = 1.0F
    blend.Colors(3) = MiddleColor

    Using b As New LinearGradientBrush(rect, blend.Colors(0), blend.Colors(3), Angle)
      b.InterpolationColors = blend

      g.FillRectangle(Brushes.White, rect)
      g.FillRectangle(b, rect)
    End Using
  End Sub

  ' Selects a node that is clicked on its label or tag text.
  Private Sub Me_MouseDown(ByVal sender As Object, ByVal e As MouseEventArgs) Handles MyBase.MouseDown
    Dim clickedNode As TreeNode = Me.GetNodeAt(e.X, e.Y)
    If clickedNode Is Nothing Then Exit Sub
    If NodeBounds(clickedNode).Contains(e.X, e.Y) Then
      Me.SelectedNode = clickedNode
    End If
  End Sub 'Me_MouseDown

  ' Returns the bounds of the specified node, including the region
  ' occupied by the node label and any node tag displayed.
  Private Function NodeBounds(ByVal node As TreeNode) As Rectangle

    ' Set the return value to the normal node bounds.
    Dim bounds As Rectangle = node.Bounds
    Return bounds
  End Function 'NodeBounds

End Class


C# Version
Code: Select all
using Microsoft.VisualBasic;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using ComponentFactory.Krypton.Toolkit;
using System.Drawing;
using System.Drawing.Drawing2D;

public class KryptonTreeView : TreeView
{


   KryptonManager p_Manager;
   public KryptonTreeView()
   {
      MouseDown += Me_MouseDown;
      DrawNode += Me_DrawNode;
      FormatControl();

      // Configure the TreeView control for owner-draw.
      this.DrawMode = TreeViewDrawMode.OwnerDrawText;

   }

   public KryptonManager Manager {
      get {
         if (p_Manager == null) {
            try {
               Form Form = this.FindForm;
               foreach (object Control_loopVariable in this.FindForm.Controls) {
                  Control = Control_loopVariable;
                  if (object.ReferenceEquals(Control.GetType(), typeof(KryptonManager))) {
                     p_Manager = Control;
                  }
               }
            } catch (Exception ex) {
            }
         }
         return p_Manager;
      }
      set { p_Manager = value; }
   }

   private void FormatControl()
   {
      this.Font = KryptonManager.CurrentGlobalPalette.GetContentLongTextFont(PaletteContentStyle.ButtonStandalone, PaletteState.ContextNormal);
   }

   // Draws a node.

   private void Me_DrawNode(object sender, DrawTreeNodeEventArgs e)
   {
      e.DrawDefault = false;

      // Retrieve the node font. If the node font has not been set,
      // use the TreeView font.
      Font nodeFont = e.Node.NodeFont;
      if (nodeFont == null) {
         nodeFont = ((TreeView)sender).Font;
      }

      // Draw the background and node text for a selected node.
      //(e.State And TreeNodeStates.Selected) <> 0 Then
      if (object.ReferenceEquals(e.Node, base.SelectedNode)) {

         // Draw the background of the selected node. The NodeBounds
         // method makes the highlight rectangle large enough to
         // include the text of a node tag, if one is present.
         System.Drawing.Color HighlightGradientColor1 = Manager.GlobalPalette.GetBackColor1(PaletteBorderStyle.ButtonListItem, PaletteState.CheckedTracking);
         System.Drawing.Color HighlightGradientColor2 = Manager.GlobalPalette.GetBackColor2(PaletteBorderStyle.ButtonListItem, PaletteState.CheckedTracking);
         //Dim linGrBrush As New System.Drawing.Drawing2D.LinearGradientBrush(NodeBounds(e.Node), HighlightGradientColor1, HighlightGradientColor2, Drawing2D.LinearGradientMode.Vertical)

         //e.Graphics.FillRectangle(linGrBrush, NodeBounds(e.Node))

         DrawBlendGradient(e.Graphics, NodeBounds(e.Node), HighlightGradientColor1, HighlightGradientColor1, HighlightGradientColor2, 90);

         // Draw the node text.
         SolidBrush textBrush = new SolidBrush(KryptonManager.CurrentGlobalPalette.GetContentLongTextColor1(PaletteContentStyle.ButtonListItem, PaletteState.CheckedNormal));
         e.Graphics.DrawString(e.Node.Text, nodeFont, textBrush, e.Bounds.Left, e.Bounds.Top);

         // Draw the focus rectangle large, making
         // it large enough to include the text of the node tag, if present.
         Pen focusPen = new Pen(Manager.GlobalPalette.GetBorderColor1(PaletteBorderStyle.ButtonListItem, PaletteState.CheckedNormal));
         try {
            focusPen.Width = 1;
            Rectangle focusBounds = new Rectangle(e.Node.Bounds.X, e.Node.Bounds.Y + 1, e.Node.Bounds.Width, e.Node.Bounds.Height - 2);
            DrawRoundedRectangle(e.Graphics, focusBounds, KryptonManager.CurrentGlobalPalette.GetBorderRounding(PaletteBorderStyle.ButtonListItem, PaletteState.CheckedNormal), focusPen);
         } finally {
            focusPen.Dispose();
         }

      } else {
         // Draw the node text.
         SolidBrush textBrush = new SolidBrush(KryptonManager.CurrentGlobalPalette.GetContentLongTextColor1(PaletteContentStyle.ButtonListItem, PaletteState.Normal));
         e.Graphics.DrawString(e.Node.Text, nodeFont, textBrush, e.Bounds.Left, e.Bounds.Top);
      }

   }
   //Me_DrawNode

   public void DrawRoundedRectangle(Graphics objGraphics, Rectangle rect, int m_diameter, Pen Pen)
   {
      if (m_diameter == 0) {
         objGraphics.DrawRectangle(Pen, rect);
         return;
      }

      int m_intxAxis = rect.X;
      int m_intyAxis = rect.Y;
      int m_intWidth = rect.Width;
      int m_intHeight = rect.Height;

      //Dim g As Graphics
      RectangleF BaseRect = new RectangleF(m_intxAxis, m_intyAxis, m_intWidth, m_intHeight);
      RectangleF ArcRect = new RectangleF(BaseRect.Location, new SizeF(m_diameter, m_diameter));
      //top left Arc
      objGraphics.DrawArc(Pen, ArcRect, 180, 90);
      objGraphics.DrawLine(Pen, m_intxAxis + Convert.ToInt32(m_diameter / 2), m_intyAxis, m_intxAxis + m_intWidth - Convert.ToInt32(m_diameter / 2), m_intyAxis);

      // top right arc
      ArcRect.X = BaseRect.Right - m_diameter;
      objGraphics.DrawArc(Pen, ArcRect, 270, 90);
      objGraphics.DrawLine(Pen, m_intxAxis + m_intWidth, m_intyAxis + Convert.ToInt32(m_diameter / 2), m_intxAxis + m_intWidth, m_intyAxis + m_intHeight - Convert.ToInt32(m_diameter / 2));

      // bottom right arc
      ArcRect.Y = BaseRect.Bottom - m_diameter;
      objGraphics.DrawArc(Pen, ArcRect, 0, 90);
      objGraphics.DrawLine(Pen, m_intxAxis + Convert.ToInt32(m_diameter / 2), m_intyAxis + m_intHeight, m_intxAxis + m_intWidth - Convert.ToInt32(m_diameter / 2), m_intyAxis + m_intHeight);

      // bottom left arc
      ArcRect.X = BaseRect.Left;
      objGraphics.DrawArc(Pen, ArcRect, 90, 90);
      objGraphics.DrawLine(Pen, m_intxAxis, m_intyAxis + Convert.ToInt32(m_diameter / 2), m_intxAxis, m_intyAxis + m_intHeight - Convert.ToInt32(m_diameter / 2));

   }

   public static void DrawBlendGradient(Graphics g, Rectangle rect, Color LightColor, Color DarkColor, Color MiddleColor, float Angle)
   {
      ColorBlend blend = new ColorBlend(4);

      blend.Positions[0] = 0f;
      blend.Colors[0] = LightColor;

      blend.Positions[1] = 0.8f;
      blend.Colors[1] = DarkColor;

      blend.Positions[2] = 0.8f;
      blend.Colors[2] = DarkColor;

      blend.Positions[3] = 1f;
      blend.Colors[3] = MiddleColor;

      using (LinearGradientBrush b = new LinearGradientBrush(rect, blend.Colors[0], blend.Colors[3], Angle)) {
         b.InterpolationColors = blend;

         g.FillRectangle(Brushes.White, rect);
         g.FillRectangle(b, rect);
      }
   }

   // Selects a node that is clicked on its label or tag text.
   private void Me_MouseDown(object sender, MouseEventArgs e)
   {
      TreeNode clickedNode = this.GetNodeAt(e.X, e.Y);
      if (clickedNode == null)
         return;
      if (NodeBounds(clickedNode).Contains(e.X, e.Y)) {
         this.SelectedNode = clickedNode;
      }
   }
   //Me_MouseDown

   // Returns the bounds of the specified node, including the region
   // occupied by the node label and any node tag displayed.
   private Rectangle NodeBounds(TreeNode node)
   {

      // Set the return value to the normal node bounds.
      Rectangle bounds = node.Bounds;
      return bounds;
   }
   //NodeBounds

}
Nick71
 
Posts: 18
Joined: Fri Jan 15, 2010 11:52 pm
Location: Scotland, UK

Re: Down and dirty KryptonTreeView

Postby Phil Wright » Wed Feb 23, 2011 1:06 pm

Excellent work. To get a nice border I would recommend you use a KryptonGroup and then place the customized tree view inside the Group and set it to fill the client area. Then turn off the border for the tree view and let the group provide the border.
Phil Wright
Site Admin
 
Posts: 2720
Joined: Thu Apr 13, 2006 2:55 pm
Location: Melbourne, Australia

Re: Down and dirty KryptonTreeView

Postby PIDC » Wed Feb 23, 2011 10:19 pm

It's perfect if the scrollbars are kryptonized. Thanks for the code.
PIDC
 
Posts: 22
Joined: Tue Jun 12, 2007 3:58 pm

Re: Down and dirty KryptonTreeView

Postby Angel » Mon Feb 28, 2011 6:32 pm

(UPDATE)
Hi, I've fixed the C# version, added the palette change event (and dispose), the correct drawing of the background and the content using the renderer, the font, the hot track:
Code: Select all
using Microsoft.VisualBasic;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using ComponentFactory.Krypton.Toolkit;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;

namespace AC.ExtendedRenderer.Toolkit
{
    [System.Drawing.ToolboxBitmapAttribute(typeof(System.Windows.Forms.TreeView))]
    public class KryptonTreeView : TreeView
    {

        #region "   Members   "
        private IPalette _palette;
        private PaletteRedirect _paletteRedirect;
        private PaletteBackInheritRedirect _paletteBack;
        private PaletteBorderInheritRedirect _paletteBorder;
        private PaletteContentInheritRedirect _paletteContent;
        private IDisposable _mementoContent;
        private IDisposable _mementoBack1;
        private IDisposable _mementoBack2;
        #endregion

        #region "   Ctor   "
        public KryptonTreeView()
        {
            //double buffer
            SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint, true);
            UpdateStyles();

            // Configure the TreeView control for owner-draw.
            this.DrawMode = TreeViewDrawMode.OwnerDrawText;

            // add Palette Handler
            // Cache the current global palette setting
            _palette = KryptonManager.CurrentGlobalPalette;

            // Hook into palette events
            if (_palette != null)
                _palette.PalettePaint += new EventHandler<PaletteLayoutEventArgs>(OnPalettePaint);

            // We want to be notified whenever the global palette changes
            KryptonManager.GlobalPaletteChanged += new EventHandler(OnGlobalPaletteChanged);

            // Create redirection object to the base palette
            _paletteRedirect = new PaletteRedirect(_palette);

            // Create accessor objects for the back, border and content
            _paletteBack = new PaletteBackInheritRedirect(_paletteRedirect);
            _paletteBorder = new PaletteBorderInheritRedirect(_paletteRedirect);
            _paletteContent = new PaletteContentInheritRedirect(_paletteRedirect);

        }
        #endregion

        #region "   Palette Change Event & Dispose   "
        //Kripton Palette Events
        private void OnGlobalPaletteChanged(object sender, EventArgs e)
        {
            // Unhook events from old palette
            if (_palette != null)
                _palette.PalettePaint -= new EventHandler<PaletteLayoutEventArgs>(OnPalettePaint);

            // Cache the new IPalette that is the global palette
            _palette = KryptonManager.CurrentGlobalPalette;
            _paletteRedirect.Target = _palette;

            // Hook into events for the new palette
            if (_palette != null)
            {
                _palette.PalettePaint += new EventHandler<PaletteLayoutEventArgs>(OnPalettePaint);
            }

            // Change of palette means we should repaint to show any changes
            Invalidate();
        }


        //Kripton Palette Events
        private void OnPalettePaint(object sender, PaletteLayoutEventArgs e)
        {
            // Palette indicates we might need to repaint, so lets do it
            Invalidate();
        }

        //Dispose Event
        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                if (_mementoContent != null)
                {
                    _mementoContent.Dispose();
                    _mementoContent = null;
                }

                if (_mementoBack1 != null)
                {
                    _mementoBack1.Dispose();
                    _mementoBack1 = null;
                }

                if (_mementoBack2 != null)
                {
                    _mementoBack2.Dispose();
                    _mementoBack2 = null;
                }

                // Unhook from the palette events
                if (_palette != null)
                {
                    _palette.PalettePaint -= new EventHandler<PaletteLayoutEventArgs>(OnPalettePaint);
                    _palette = null;
                }

                // Unhook from the static events, otherwise we cannot be garbage collected
                KryptonManager.GlobalPaletteChanged -= new EventHandler(OnGlobalPaletteChanged);
            }

            base.Dispose(disposing);
        }
        #endregion

        #region "   Overrides & Draw  "

        // Selects a node that is clicked on its label or tag text.
        protected override void OnMouseDown(MouseEventArgs e)
        {
            TreeNode clickedNode = this.GetNodeAt(e.X, e.Y);
            if (clickedNode == null)
                return;
            if (NodeBounds(clickedNode).Contains(e.X, e.Y))
            {
                this.SelectedNode = clickedNode;
            }
        }

        //create Graphics Path
        private GraphicsPath CreateRectGraphicsPath(Rectangle rect)
        {
            GraphicsPath path = new GraphicsPath();
            path.AddRectangle(rect);
            return path;
        }

        private PaletteState GetNodeState(DrawTreeNodeEventArgs e)
        {
            // Find the correct state when getting button values
            if (!Enabled)
                return PaletteState.Disabled;
            else
            {
                if (e.State == TreeNodeStates.Hot)
                        return PaletteState.Tracking;
                else
                    return PaletteState.Pressed;
            }
        }
        // Draws a node.
        protected override void OnDrawNode(DrawTreeNodeEventArgs e)
        {
            e.DrawDefault = false;
            Graphics g = e.Graphics;

            // Get the renderer associated with this palette
            IRenderer renderer = _palette.GetRenderer();

            // We want to anti alias the drawing for nice smooth curves
            g.SmoothingMode = SmoothingMode.AntiAlias;
            g.CompositingQuality = CompositingQuality.HighQuality;
            g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit;

            // Create the rendering context that is passed into all renderer calls
            using (RenderContext renderContext = new RenderContext(this, g, NodeBounds(e.Node), renderer))
            {

                // we need to find the correct palette state based on if the mouse
                // is over the control if the mouse button is pressed down or not.
                PaletteState buttonState = PaletteState.CheckedPressed;

                if (this.Enabled == false) buttonState = PaletteState.Disabled;

                // Create a rectangle inset, this is where we will draw the node
                Rectangle innerRect = NodeBounds(e.Node);
                Rectangle innerContent = new Rectangle(innerRect.X + 1, innerRect.Y + 1, innerRect.Width - 2, innerRect.Height - 2);

                // Set the style of control we want to draw
                _paletteBack.Style = PaletteBackStyle.ButtonStandalone;
                _paletteBorder.Style = PaletteBorderStyle.ButtonStandalone;
                _paletteContent.Style = PaletteContentStyle.ButtonStandalone;

                // Get the color and font used to draw the text
                Color textColor = _palette.GetContentShortTextColor1(PaletteContentStyle.ButtonStandalone, buttonState);
                Font textFont = _palette.GetContentShortTextFont(PaletteContentStyle.ButtonStandalone, buttonState);

                // Draw the background and node text for a selected node.
                //(e.State And TreeNodeStates.Selected) <> 0 Then


                if (e.State == TreeNodeStates.Hot || e.State == TreeNodeStates.Selected || (e.State & TreeNodeStates.Focused) != 0)
                {
                    buttonState = GetNodeState(e);

                    //clear contents
                    g.FillRectangle(new SolidBrush(this.BackColor), innerRect.X - 1, innerRect.Y - 1, innerRect.Width + 2, innerRect.Height + 2);

                    //////////////////////////////////////////////////////////////////////////////////
                    // In case the border has a rounded effect we need to get the background path   //
                    // to draw from the border part of the renderer. It will return a path that is  //
                    // appropriate for use drawing within the border settings.                      //
                    //////////////////////////////////////////////////////////////////////////////////
                    using (GraphicsPath path = renderer.RenderStandardBorder.GetBackPath(renderContext, innerRect, _paletteBorder, VisualOrientation.Top, buttonState))
                    {
                        // Ask renderer to draw the background
                        _mementoBack2 = renderer.RenderStandardBack.DrawBack(renderContext, innerContent, path, _paletteBack, VisualOrientation.Top, buttonState, _mementoBack2);
                    }

                    // Now we draw the border of the inner area, also in ButtonStandalone style
                    renderer.RenderStandardBorder.DrawBorder(renderContext, innerRect, _paletteBorder, VisualOrientation.Bottom, buttonState);


                    // Draw the node text.
                    using (Brush textBrush = new SolidBrush(textColor))
                    {
                        // We want to anti alias the drawing for nice smooth curves
                        g.DrawString(e.Node.Text, textFont, textBrush, e.Bounds.Left, e.Bounds.Top);
                    }
                }
                else
                {
                    // Draw the node text.
                    textColor = this.ForeColor;
                    using (Brush textBrush = new SolidBrush(textColor))
                        g.DrawString(e.Node.Text, textFont, textBrush, e.Bounds.Left, e.Bounds.Top);
                }
            }
        }

        // Returns the bounds of the specified node, including the region
        // occupied by the node label and any node tag displayed.
        private Rectangle NodeBounds(TreeNode node)
        {

            // Set the return value to the normal node bounds.
            Rectangle bounds = node.Bounds;
            return bounds;
        }
        #endregion
    }
}


Image
Thanks for sharing
regards /// Angel
Angel
 
Posts: 251
Joined: Tue Aug 07, 2007 5:12 pm
Location: Lugano, Switzerland

Re: Down and dirty KryptonTreeView

Postby Angel » Tue Mar 01, 2011 6:52 pm

(UPDATE)
Fixed the string measurement for the correct font, fixed the lost focus behaviour:
Code: Select all
using Microsoft.VisualBasic;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using ComponentFactory.Krypton.Toolkit;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;

namespace AC.ExtendedRenderer.Toolkit
{
    [System.Drawing.ToolboxBitmapAttribute(typeof(System.Windows.Forms.TreeView))]
    public class KryptonTreeView : TreeView
    {

        #region "   Members   "
        private bool _hasFocus = false;
        private IPalette _palette;
        private PaletteRedirect _paletteRedirect;
        private PaletteBackInheritRedirect _paletteBack;
        private PaletteBorderInheritRedirect _paletteBorder;
        private PaletteContentInheritRedirect _paletteContent;
        private IDisposable _mementoContent;
        private IDisposable _mementoBack1;
        private IDisposable _mementoBack2;
        #endregion

        #region "   Ctor   "
        public KryptonTreeView()
        {
            //double buffer
            SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint, true);
            UpdateStyles();

            // Configure the TreeView control for owner-draw.
            this.DrawMode = TreeViewDrawMode.OwnerDrawText;

            // add Palette Handler
            // Cache the current global palette setting
            _palette = KryptonManager.CurrentGlobalPalette;

            // Hook into palette events
            if (_palette != null)
                _palette.PalettePaint += new EventHandler<PaletteLayoutEventArgs>(OnPalettePaint);

            // We want to be notified whenever the global palette changes
            KryptonManager.GlobalPaletteChanged += new EventHandler(OnGlobalPaletteChanged);

            // Create redirection object to the base palette
            _paletteRedirect = new PaletteRedirect(_palette);

            // Create accessor objects for the back, border and content
            _paletteBack = new PaletteBackInheritRedirect(_paletteRedirect);
            _paletteBorder = new PaletteBorderInheritRedirect(_paletteRedirect);
            _paletteContent = new PaletteContentInheritRedirect(_paletteRedirect);

        }
        #endregion

        #region "   Palette Change Event & Dispose   "
        //Kripton Palette Events
        private void OnGlobalPaletteChanged(object sender, EventArgs e)
        {
            // Unhook events from old palette
            if (_palette != null)
                _palette.PalettePaint -= new EventHandler<PaletteLayoutEventArgs>(OnPalettePaint);

            // Cache the new IPalette that is the global palette
            _palette = KryptonManager.CurrentGlobalPalette;
            _paletteRedirect.Target = _palette;

            // Hook into events for the new palette
            if (_palette != null)
            {
                _palette.PalettePaint += new EventHandler<PaletteLayoutEventArgs>(OnPalettePaint);
            }

            // Change of palette means we should repaint to show any changes
            Invalidate();
        }


        //Kripton Palette Events
        private void OnPalettePaint(object sender, PaletteLayoutEventArgs e)
        {
            // Palette indicates we might need to repaint, so lets do it
            Invalidate();
        }

        //Dispose Event
        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                if (_mementoContent != null)
                {
                    _mementoContent.Dispose();
                    _mementoContent = null;
                }

                if (_mementoBack1 != null)
                {
                    _mementoBack1.Dispose();
                    _mementoBack1 = null;
                }

                if (_mementoBack2 != null)
                {
                    _mementoBack2.Dispose();
                    _mementoBack2 = null;
                }

                // Unhook from the palette events
                if (_palette != null)
                {
                    _palette.PalettePaint -= new EventHandler<PaletteLayoutEventArgs>(OnPalettePaint);
                    _palette = null;
                }

                // Unhook from the static events, otherwise we cannot be garbage collected
                KryptonManager.GlobalPaletteChanged -= new EventHandler(OnGlobalPaletteChanged);
            }

            base.Dispose(disposing);
        }
        #endregion

        #region "   Overrides & Draw  "
        protected override void OnLostFocus(EventArgs e)
        {
            _hasFocus = false;
            Invalidate();
            base.OnLostFocus(e);
        }

        protected override void OnGotFocus(EventArgs e)
        {
            _hasFocus = true;
            Invalidate();
            base.OnGotFocus(e);
        }

        // Selects a node that is clicked on its label or tag text.
        protected override void OnMouseDown(MouseEventArgs e)
        {
            TreeNode clickedNode = this.GetNodeAt(e.X, e.Y);
            if (clickedNode == null)
                return;
            if (NodeBounds(clickedNode).Contains(e.X, e.Y))
            {
                this.SelectedNode = clickedNode;
            }
        }

        //create Graphics Path
        private GraphicsPath CreateRectGraphicsPath(Rectangle rect)
        {
            GraphicsPath path = new GraphicsPath();
            path.AddRectangle(rect);
            return path;
        }

        private PaletteState GetNodeState(DrawTreeNodeEventArgs e)
        {
            // Find the correct state when getting button values
            if (!Enabled)
                return PaletteState.Disabled;
            else
            {
                if (e.State == TreeNodeStates.Hot)
                    return PaletteState.Tracking;
                else
                    return PaletteState.Pressed;
            }
        }

        // Draws a node.
        protected override void OnDrawNode(DrawTreeNodeEventArgs e)
        {
            e.DrawDefault = false;
            Graphics g = e.Graphics;

            // Get the renderer associated with this palette
            IRenderer renderer = _palette.GetRenderer();

            // We want to anti alias the drawing for nice smooth curves
            g.SmoothingMode = SmoothingMode.AntiAlias;
            g.CompositingQuality = CompositingQuality.HighQuality;
            g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit;

            // Create the rendering context that is passed into all renderer calls
            using (RenderContext renderContext = new RenderContext(this, g, NodeBounds(e.Node), renderer))
            {

                // we need to find the correct palette state based on if the mouse
                // is over the control if the mouse button is pressed down or not.
                PaletteState buttonState = PaletteState.CheckedPressed;

                // Create a rectangle inset, this is where we will draw the node
                Rectangle innerRect = NodeBounds(e.Node);
                Rectangle innerContent = new Rectangle(innerRect.X + 1, innerRect.Y + 1, innerRect.Width - 2, innerRect.Height - 2);

                // Set the style of control we want to draw
                _paletteBack.Style = PaletteBackStyle.ButtonStandalone;
                _paletteBorder.Style = PaletteBorderStyle.ButtonStandalone;
                _paletteContent.Style = PaletteContentStyle.ButtonStandalone;

                // Get the color and font used to draw the text
                Color textColor = _palette.GetContentShortTextColor1(PaletteContentStyle.ButtonStandalone, buttonState);
                Font textFont = _palette.GetContentShortTextFont(PaletteContentStyle.ButtonStandalone, buttonState);

                //do we have enought room for the text? --> let expand it
                SizeF TextLenght = g.MeasureString(e.Node.Text, textFont);
                innerRect.Width = (int)TextLenght.Width;
                innerContent.Width = (int)TextLenght.Width - 2;

                //clear contents
                g.FillRectangle(new SolidBrush(this.BackColor), innerRect.X - 1, innerRect.Y, innerRect.Width + 2, innerRect.Height);


                //draw only for some node states
                if (e.State == TreeNodeStates.Hot || e.State == TreeNodeStates.Selected || (e.State & TreeNodeStates.Focused) != 0)
                {
                    //get button state
                    buttonState = GetNodeState(e);

                    //lost focus
                    if (!_hasFocus) buttonState = PaletteState.Normal;

                    //force disabled mode
                    if (this.Enabled == false) buttonState = PaletteState.Disabled;

                    //////////////////////////////////////////////////////////////////////////////////
                    // In case the border has a rounded effect we need to get the background path   //
                    // to draw from the border part of the renderer. It will return a path that is  //
                    // appropriate for use drawing within the border settings.                      //
                    //////////////////////////////////////////////////////////////////////////////////
                    using (GraphicsPath path = renderer.RenderStandardBorder.GetBackPath(renderContext, innerRect, _paletteBorder, VisualOrientation.Top, buttonState))
                    {
                        // Ask renderer to draw the background
                        _mementoBack2 = renderer.RenderStandardBack.DrawBack(renderContext, innerContent, path, _paletteBack, VisualOrientation.Top, buttonState, _mementoBack2);
                    }

                    // Now we draw the border of the inner area, also in ButtonStandalone style
                    renderer.RenderStandardBorder.DrawBorder(renderContext, innerRect, _paletteBorder, VisualOrientation.Bottom, buttonState);

                    // Draw the node text.
                    using (Brush textBrush = new SolidBrush(textColor))
                    {
                        // We want to anti alias the drawing for nice smooth curves
                        g.DrawString(e.Node.Text, textFont, textBrush, e.Bounds.Left, e.Bounds.Top);
                    }
                }
                else
                {
                    // Draw the node text.
                    textColor = this.ForeColor;
                    using (Brush textBrush = new SolidBrush(textColor))
                        g.DrawString(e.Node.Text, textFont, textBrush, e.Bounds.Left, e.Bounds.Top);
                }
            }
        }

        // Returns the bounds of the specified node, including the region
        // occupied by the node label and any node tag displayed.
        private Rectangle NodeBounds(TreeNode node)
        {

            // Set the return value to the normal node bounds.
            Rectangle bounds = node.Bounds;
            return bounds;
        }
        #endregion
    }
}


Regards /// Angel
Angel
 
Posts: 251
Joined: Tue Aug 07, 2007 5:12 pm
Location: Lugano, Switzerland

Re: Down and dirty KryptonTreeView

Postby Nick71 » Tue Mar 01, 2011 10:07 pm

Great work Angel, you're a genius, now works a treat. If anyone else (like me) is stuck in a VB environment, the translation of Angel's work to VB is below.

Cheers
Nick

Code: Select all
Imports System.Collections
Imports System.Collections.Generic
Imports System.Data
Imports System.Diagnostics
Imports ComponentFactory.Krypton.Toolkit
Imports System.Drawing
Imports System.Drawing.Drawing2D
Imports System.Windows.Forms


<System.Drawing.ToolboxBitmapAttribute(GetType(System.Windows.Forms.TreeView))> _
Public Class KryptonTreeView
  Inherits TreeView

#Region "   Members   "
  Private _hasFocus As Boolean = False
  Private _palette As IPalette
  Private _paletteRedirect As PaletteRedirect
  Private _paletteBack As PaletteBackInheritRedirect
  Private _paletteBorder As PaletteBorderInheritRedirect
  Private _paletteContent As PaletteContentInheritRedirect
  Private _mementoContent As IDisposable
  Private _mementoBack1 As IDisposable
  Private _mementoBack2 As IDisposable
#End Region

#Region "   Ctor   "
  Public Sub New()
    'double buffer
    SetStyle(ControlStyles.OptimizedDoubleBuffer Or ControlStyles.AllPaintingInWmPaint, True)
    UpdateStyles()

    ' Configure the TreeView control for owner-draw.
    Me.DrawMode = TreeViewDrawMode.OwnerDrawText

    ' add Palette Handler
    ' Cache the current global palette setting
    _palette = KryptonManager.CurrentGlobalPalette

    ' Hook into palette events
    If _palette IsNot Nothing Then
      AddHandler _palette.PalettePaint, AddressOf OnPalettePaint
    End If

    ' We want to be notified whenever the global palette changes
    AddHandler KryptonManager.GlobalPaletteChanged, AddressOf OnGlobalPaletteChanged

    ' Create redirection object to the base palette
    _paletteRedirect = New PaletteRedirect(_palette)

    ' Create accessor objects for the back, border and content
    _paletteBack = New PaletteBackInheritRedirect(_paletteRedirect)
    _paletteBorder = New PaletteBorderInheritRedirect(_paletteRedirect)

    _paletteContent = New PaletteContentInheritRedirect(_paletteRedirect)
  End Sub
#End Region

#Region "   Palette Change Event & Dispose   "
  'Krypton Palette Events
  Private Sub OnGlobalPaletteChanged(ByVal sender As Object, ByVal e As EventArgs)
    ' Unhook events from old palette
    If _palette IsNot Nothing Then
      RemoveHandler _palette.PalettePaint, AddressOf OnPalettePaint
    End If

    ' Cache the new IPalette that is the global palette
    _palette = KryptonManager.CurrentGlobalPalette
    _paletteRedirect.Target = _palette

    ' Hook into events for the new palette
    If _palette IsNot Nothing Then
      AddHandler _palette.PalettePaint, AddressOf OnPalettePaint
    End If

    ' Change of palette means we should repaint to show any changes
    Invalidate()
  End Sub


  'Krypton Palette Events
  Private Sub OnPalettePaint(ByVal sender As Object, ByVal e As PaletteLayoutEventArgs)
    ' Palette indicates we might need to repaint, so lets do it
    Invalidate()
  End Sub

  'Dispose Event
  Protected Overrides Sub Dispose(ByVal disposing As Boolean)
    If disposing Then
      If _mementoContent IsNot Nothing Then
        _mementoContent.Dispose()
        _mementoContent = Nothing
      End If

      If _mementoBack1 IsNot Nothing Then
        _mementoBack1.Dispose()
        _mementoBack1 = Nothing
      End If

      If _mementoBack2 IsNot Nothing Then
        _mementoBack2.Dispose()
        _mementoBack2 = Nothing
      End If

      ' Unhook from the palette events
      If _palette IsNot Nothing Then
        RemoveHandler _palette.PalettePaint, AddressOf OnPalettePaint
        _palette = Nothing
      End If

      ' Unhook from the static events, otherwise we cannot be garbage collected
      RemoveHandler KryptonManager.GlobalPaletteChanged, AddressOf OnGlobalPaletteChanged
    End If

    MyBase.Dispose(disposing)
  End Sub
#End Region

#Region "   Overrides & Draw  "
  Protected Overrides Sub OnLostFocus(ByVal e As EventArgs)
    _hasFocus = False
    Invalidate()
    MyBase.OnLostFocus(e)
  End Sub

  Protected Overrides Sub OnGotFocus(ByVal e As EventArgs)
    _hasFocus = True
    Invalidate()
    MyBase.OnGotFocus(e)
  End Sub

  ' Selects a node that is clicked on its label or tag text.
  Protected Overrides Sub OnMouseDown(ByVal e As MouseEventArgs)
    Dim clickedNode As TreeNode = Me.GetNodeAt(e.X, e.Y)
    If clickedNode Is Nothing Then
      Return
    End If
    If NodeBounds(clickedNode).Contains(e.X, e.Y) Then
      Me.SelectedNode = clickedNode
    End If
  End Sub

  'create Graphics Path
  Private Function CreateRectGraphicsPath(ByVal rect As Rectangle) As GraphicsPath
    Dim path As New GraphicsPath()
    path.AddRectangle(rect)
    Return path
  End Function

  Private Function GetNodeState(ByVal e As DrawTreeNodeEventArgs) As PaletteState
    ' Find the correct state when getting button values
    If Not Enabled Then
      Return PaletteState.Disabled
    Else
      If e.State = TreeNodeStates.Hot Then
        Return PaletteState.Tracking
      Else
        Return PaletteState.Pressed
      End If
    End If
  End Function

  ' Draws a node.
  Protected Overrides Sub OnDrawNode(ByVal e As DrawTreeNodeEventArgs)
    e.DrawDefault = False
    Dim g As Graphics = e.Graphics

    ' Get the renderer associated with this palette
    Dim renderer As IRenderer = _palette.GetRenderer()

    ' We want to anti alias the drawing for nice smooth curves
    g.SmoothingMode = SmoothingMode.AntiAlias
    g.CompositingQuality = CompositingQuality.HighQuality
    g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit

    ' Create the rendering context that is passed into all renderer calls
    Using renderContext As New RenderContext(Me, g, NodeBounds(e.Node), renderer)

      ' we need to find the correct palette state based on if the mouse
      ' is over the control if the mouse button is pressed down or not.
      Dim buttonState As PaletteState = PaletteState.CheckedPressed

      ' Create a rectangle inset, this is where we will draw the node
      Dim innerRect As Rectangle = NodeBounds(e.Node)
      Dim innerContent As New Rectangle(innerRect.X + 1, innerRect.Y + 1, innerRect.Width - 2, innerRect.Height - 2)

      ' Set the style of control we want to draw
      _paletteBack.Style = PaletteBackStyle.ButtonStandalone
      _paletteBorder.Style = PaletteBorderStyle.ButtonStandalone
      _paletteContent.Style = PaletteContentStyle.ButtonStandalone

      ' Get the color and font used to draw the text
      Dim textColor As Color = _palette.GetContentShortTextColor1(PaletteContentStyle.ButtonStandalone, buttonState)
      Dim textFont As Font = _palette.GetContentShortTextFont(PaletteContentStyle.ButtonStandalone, buttonState)

      'do we have enought room for the text? --> let expand it
      Dim TextLenght As SizeF = g.MeasureString(e.Node.Text, textFont)
      innerRect.Width = CInt(Math.Truncate(TextLenght.Width))
      innerContent.Width = CInt(Math.Truncate(TextLenght.Width)) - 2

      'clear contents
      g.FillRectangle(New SolidBrush(Me.BackColor), innerRect.X - 1, innerRect.Y, innerRect.Width + 2, innerRect.Height)


      'draw only for some node states
      If e.State = TreeNodeStates.Hot OrElse e.State = TreeNodeStates.Selected OrElse (e.State And TreeNodeStates.Focused) <> 0 Then
        'get button state
        buttonState = GetNodeState(e)

        'lost focus
        If Not _hasFocus Then
          buttonState = PaletteState.Normal
        End If

        'force disabled mode
        If Me.Enabled = False Then
          buttonState = PaletteState.Disabled
        End If

        '''///////////////////////////////////////////////////////////////////////////////
        ' In case the border has a rounded effect we need to get the background path   //
        ' to draw from the border part of the renderer. It will return a path that is  //
        ' appropriate for use drawing within the border settings.                      //
        '''///////////////////////////////////////////////////////////////////////////////
        Using path As GraphicsPath = renderer.RenderStandardBorder.GetBackPath(renderContext, innerRect, _paletteBorder, VisualOrientation.Top, buttonState)
          ' Ask renderer to draw the background
          _mementoBack2 = renderer.RenderStandardBack.DrawBack(renderContext, innerContent, path, _paletteBack, VisualOrientation.Top, buttonState, _
           _mementoBack2)
        End Using

        ' Now we draw the border of the inner area, also in ButtonStandalone style
        renderer.RenderStandardBorder.DrawBorder(renderContext, innerRect, _paletteBorder, VisualOrientation.Bottom, buttonState)

        ' Draw the node text.
        Using textBrush As Brush = New SolidBrush(textColor)
          ' We want to anti alias the drawing for nice smooth curves
          g.DrawString(e.Node.Text, textFont, textBrush, e.Bounds.Left, e.Bounds.Top)
        End Using
      Else
        ' Draw the node text.
        textColor = Me.ForeColor
        Using textBrush As Brush = New SolidBrush(textColor)
          g.DrawString(e.Node.Text, textFont, textBrush, e.Bounds.Left, e.Bounds.Top)
        End Using
      End If
    End Using
  End Sub

  ' Returns the bounds of the specified node, including the region
  ' occupied by the node label and any node tag displayed.
  Private Function NodeBounds(ByVal node As TreeNode) As Rectangle

    ' Set the return value to the normal node bounds.
    Dim bounds As Rectangle = node.Bounds
    Return bounds
  End Function
#End Region
End Class
Nick71
 
Posts: 18
Joined: Fri Jan 15, 2010 11:52 pm
Location: Scotland, UK

Re: Down and dirty KryptonTreeView

Postby Angel » Tue Mar 01, 2011 10:24 pm

Thank you (not true), but the fact is that your approach was better than mine ...
this update is for the forecolor.
Code: Select all
using Microsoft.VisualBasic;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using ComponentFactory.Krypton.Toolkit;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;

namespace AC.ExtendedRenderer.Toolkit
{
    [System.Drawing.ToolboxBitmapAttribute(typeof(System.Windows.Forms.TreeView))]
    public class KryptonTreeView : TreeView
    {

        #region "   Members   "
        private bool _hasFocus = false;
        private IPalette _palette;
        private PaletteRedirect _paletteRedirect;
        private PaletteBackInheritRedirect _paletteBack;
        private PaletteBorderInheritRedirect _paletteBorder;
        private PaletteContentInheritRedirect _paletteContent;
        private IDisposable _mementoContent;
        private IDisposable _mementoBack1;
        private IDisposable _mementoBack2;
        #endregion

        #region "   Ctor   "
        public KryptonTreeView()
        {
            //double buffer
            SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint, true);
            UpdateStyles();

            // Configure the TreeView control for owner-draw.
            this.DrawMode = TreeViewDrawMode.OwnerDrawText;

            // add Palette Handler
            // Cache the current global palette setting
            _palette = KryptonManager.CurrentGlobalPalette;

            // Hook into palette events
            if (_palette != null)
                _palette.PalettePaint += new EventHandler<PaletteLayoutEventArgs>(OnPalettePaint);

            // We want to be notified whenever the global palette changes
            KryptonManager.GlobalPaletteChanged += new EventHandler(OnGlobalPaletteChanged);

            // Create redirection object to the base palette
            _paletteRedirect = new PaletteRedirect(_palette);

            // Create accessor objects for the back, border and content
            _paletteBack = new PaletteBackInheritRedirect(_paletteRedirect);
            _paletteBorder = new PaletteBorderInheritRedirect(_paletteRedirect);
            _paletteContent = new PaletteContentInheritRedirect(_paletteRedirect);

        }
        #endregion

        #region "   Palette Change Event & Dispose   "
        //Krypton Palette Events
        private void OnGlobalPaletteChanged(object sender, EventArgs e)
        {
            // Unhook events from old palette
            if (_palette != null)
                _palette.PalettePaint -= new EventHandler<PaletteLayoutEventArgs>(OnPalettePaint);

            // Cache the new IPalette that is the global palette
            _palette = KryptonManager.CurrentGlobalPalette;
            _paletteRedirect.Target = _palette;

            // Hook into events for the new palette
            if (_palette != null)
            {
                _palette.PalettePaint += new EventHandler<PaletteLayoutEventArgs>(OnPalettePaint);
            }

            // Change of palette means we should repaint to show any changes
            Invalidate();
        }


        //Kripton Palette Events
        private void OnPalettePaint(object sender, PaletteLayoutEventArgs e)
        {
            // Palette indicates we might need to repaint, so lets do it
            Invalidate();
        }

        //Dispose Event
        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                if (_mementoContent != null)
                {
                    _mementoContent.Dispose();
                    _mementoContent = null;
                }

                if (_mementoBack1 != null)
                {
                    _mementoBack1.Dispose();
                    _mementoBack1 = null;
                }

                if (_mementoBack2 != null)
                {
                    _mementoBack2.Dispose();
                    _mementoBack2 = null;
                }

                // Unhook from the palette events
                if (_palette != null)
                {
                    _palette.PalettePaint -= new EventHandler<PaletteLayoutEventArgs>(OnPalettePaint);
                    _palette = null;
                }

                // Unhook from the static events, otherwise we cannot be garbage collected
                KryptonManager.GlobalPaletteChanged -= new EventHandler(OnGlobalPaletteChanged);
            }

            base.Dispose(disposing);
        }
        #endregion

        #region "   Overrides & Draw  "
        protected override void OnLostFocus(EventArgs e)
        {
            _hasFocus = false;
            Invalidate();
            base.OnLostFocus(e);
        }

        protected override void OnGotFocus(EventArgs e)
        {
            _hasFocus = true;
            Invalidate();
            base.OnGotFocus(e);
        }

        // Selects a node that is clicked on its label or tag text.
        protected override void OnMouseDown(MouseEventArgs e)
        {
            TreeNode clickedNode = this.GetNodeAt(e.X, e.Y);
            if (clickedNode == null)
                return;
            if (NodeBounds(clickedNode).Contains(e.X, e.Y))
            {
                this.SelectedNode = clickedNode;
            }
        }

        //create Graphics Path
        private GraphicsPath CreateRectGraphicsPath(Rectangle rect)
        {
            GraphicsPath path = new GraphicsPath();
            path.AddRectangle(rect);
            return path;
        }

        private PaletteState GetNodeState(DrawTreeNodeEventArgs e)
        {
            // Find the correct state when getting button values
            if (!Enabled)
                return PaletteState.Disabled;
            else
            {
                if (e.State == TreeNodeStates.Hot)
                    return PaletteState.Tracking;
                else
                    return PaletteState.Pressed;
            }
        }

        // Draws a node.
        protected override void OnDrawNode(DrawTreeNodeEventArgs e)
        {
            e.DrawDefault = false;
            Graphics g = e.Graphics;

            // Get the renderer associated with this palette
            IRenderer renderer = _palette.GetRenderer();

            // We want to anti alias the drawing for nice smooth curves
            g.SmoothingMode = SmoothingMode.AntiAlias;
            g.CompositingQuality = CompositingQuality.HighQuality;
            g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit;

            // Create the rendering context that is passed into all renderer calls
            using (RenderContext renderContext = new RenderContext(this, g, NodeBounds(e.Node), renderer))
            {

                // we need to find the correct palette state based on if the mouse
                // is over the control if the mouse button is pressed down or not.
                PaletteState buttonState = PaletteState.CheckedPressed;

                // Create a rectangle inset, this is where we will draw the node
                Rectangle innerRect = NodeBounds(e.Node);
                Rectangle innerContent = new Rectangle(innerRect.X + 1, innerRect.Y + 1, innerRect.Width - 2, innerRect.Height - 2);

                // Set the style of control we want to draw
                _paletteBack.Style = PaletteBackStyle.ButtonStandalone;
                _paletteBorder.Style = PaletteBorderStyle.ButtonStandalone;
                _paletteContent.Style = PaletteContentStyle.ButtonStandalone;

                // Get the color and font used to draw the text
                Color textColor = _palette.GetContentShortTextColor1(PaletteContentStyle.ButtonStandalone, buttonState);
                Font textFont = _palette.GetContentShortTextFont(PaletteContentStyle.ButtonStandalone, buttonState);

                //do we have enought room for the text? --> let expand it
                SizeF TextLenght = g.MeasureString(e.Node.Text, textFont);
                innerRect.Width = (int)TextLenght.Width;
                innerContent.Width = (int)TextLenght.Width - 2;

                //clear contents
                g.FillRectangle(new SolidBrush(this.BackColor), innerRect.X - 1, innerRect.Y, innerRect.Width + 2, innerRect.Height);


                //draw only for some node states
                if (e.State == TreeNodeStates.Hot || e.State == TreeNodeStates.Selected || (e.State & TreeNodeStates.Focused) != 0)
                {
                    //get button state
                    buttonState = GetNodeState(e);

                    //lost focus
                    if (!_hasFocus) buttonState = PaletteState.Normal;

                    //force disabled mode
                    if (this.Enabled == false) buttonState = PaletteState.Disabled;

                    //////////////////////////////////////////////////////////////////////////////////
                    // In case the border has a rounded effect we need to get the background path   //
                    // to draw from the border part of the renderer. It will return a path that is  //
                    // appropriate for use drawing within the border settings.                      //
                    //////////////////////////////////////////////////////////////////////////////////

                    // Get the color and font used to draw the text
                    textColor = _palette.GetContentShortTextColor1(PaletteContentStyle.ButtonStandalone, buttonState);

                    using (GraphicsPath path = renderer.RenderStandardBorder.GetBackPath(renderContext, innerRect, _paletteBorder, VisualOrientation.Top, buttonState))
                    {
                        // Ask renderer to draw the background
                        _mementoBack2 = renderer.RenderStandardBack.DrawBack(renderContext, innerContent, path, _paletteBack, VisualOrientation.Top, buttonState, _mementoBack2);
                    }

                    // Now we draw the border of the inner area, also in ButtonStandalone style
                    renderer.RenderStandardBorder.DrawBorder(renderContext, innerRect, _paletteBorder, VisualOrientation.Bottom, buttonState);

                    // Draw the node text.
                    using (Brush textBrush = new SolidBrush(textColor))
                    {
                        // We want to anti alias the drawing for nice smooth curves
                        g.DrawString(e.Node.Text, textFont, textBrush, e.Bounds.Left, e.Bounds.Top);
                    }
                }
                else
                {
                    // Get the color and font used to draw the text
                    try
                    {
                        textColor = _palette.ColorTable.MenuItemText; 
                        //textColor = _palette.GetContentShortTextColor1(PaletteContentStyle.LabelNormalControl, buttonState);
                    }
                    catch (Exception ex)
                    {
                        Debug.WriteLine(ex.Message);
                        textColor = this.ForeColor;
                    }
                    // Draw the node text.
                    using (Brush textBrush = new SolidBrush(textColor))
                        g.DrawString(e.Node.Text, textFont, textBrush, e.Bounds.Left, e.Bounds.Top);
                }
            }
        }

        // Returns the bounds of the specified node, including the region
        // occupied by the node label and any node tag displayed.
        private Rectangle NodeBounds(TreeNode node)
        {

            // Set the return value to the normal node bounds.
            Rectangle bounds = node.Bounds;
            return bounds;
        }
        #endregion
    }
}



Regards /// Angel
Angel
 
Posts: 251
Joined: Tue Aug 07, 2007 5:12 pm
Location: Lugano, Switzerland

Re: Down and dirty KryptonTreeView

Postby Nick71 » Wed Mar 02, 2011 12:38 am

Thanks Angel. I made a few small changes to fit in with the way a list view renders (my treeview sits alongside a listview, so makes sense in my app).

Regards
Nick

C#
Code: Select all
using Microsoft.VisualBasic;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using ComponentFactory.Krypton.Toolkit;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;

namespace AC.ExtendedRenderer.Toolkit
{
    [System.Drawing.ToolboxBitmapAttribute(typeof(System.Windows.Forms.TreeView))]
    public class KryptonTreeView : TreeView
    {

        #region "   Members   "
        private bool _hasFocus = false;
        private IPalette _palette;
        private PaletteRedirect _paletteRedirect;
        private PaletteBackInheritRedirect _paletteBack;
        private PaletteBorderInheritRedirect _paletteBorder;
        private PaletteContentInheritRedirect _paletteContent;
        private IDisposable _mementoContent;
        private IDisposable _mementoBack1;
        private IDisposable _mementoBack2;
        #endregion

        #region "   Ctor   "
        public KryptonTreeView()
        {
            //double buffer
            SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint, true);
            UpdateStyles();

            // Configure the TreeView control for owner-draw.
            this.DrawMode = TreeViewDrawMode.OwnerDrawText;

            // add Palette Handler
            // Cache the current global palette setting
            _palette = KryptonManager.CurrentGlobalPalette;

            // Hook into palette events
            if (_palette != null)
                _palette.PalettePaint += new EventHandler<PaletteLayoutEventArgs>(OnPalettePaint);

            // We want to be notified whenever the global palette changes
            KryptonManager.GlobalPaletteChanged += new EventHandler(OnGlobalPaletteChanged);

            // Create redirection object to the base palette
            _paletteRedirect = new PaletteRedirect(_palette);

            // Create accessor objects for the back, border and content
            _paletteBack = new PaletteBackInheritRedirect(_paletteRedirect);
            _paletteBorder = new PaletteBorderInheritRedirect(_paletteRedirect);
            _paletteContent = new PaletteContentInheritRedirect(_paletteRedirect);

        }
        #endregion

        #region "   Palette Change Event & Dispose   "
        //Krypton Palette Events
        private void OnGlobalPaletteChanged(object sender, EventArgs e)
        {
            // Unhook events from old palette
            if (_palette != null)
                _palette.PalettePaint -= new EventHandler<PaletteLayoutEventArgs>(OnPalettePaint);

            // Cache the new IPalette that is the global palette
            _palette = KryptonManager.CurrentGlobalPalette;
            _paletteRedirect.Target = _palette;

            // Hook into events for the new palette
            if (_palette != null)
            {
                _palette.PalettePaint += new EventHandler<PaletteLayoutEventArgs>(OnPalettePaint);
            }

            // Change of palette means we should repaint to show any changes
            Invalidate();
        }


        //Kripton Palette Events
        private void OnPalettePaint(object sender, PaletteLayoutEventArgs e)
        {
            // Palette indicates we might need to repaint, so lets do it
            Invalidate();
        }

        //Dispose Event
        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                if (_mementoContent != null)
                {
                    _mementoContent.Dispose();
                    _mementoContent = null;
                }

                if (_mementoBack1 != null)
                {
                    _mementoBack1.Dispose();
                    _mementoBack1 = null;
                }

                if (_mementoBack2 != null)
                {
                    _mementoBack2.Dispose();
                    _mementoBack2 = null;
                }

                // Unhook from the palette events
                if (_palette != null)
                {
                    _palette.PalettePaint -= new EventHandler<PaletteLayoutEventArgs>(OnPalettePaint);
                    _palette = null;
                }

                // Unhook from the static events, otherwise we cannot be garbage collected
                KryptonManager.GlobalPaletteChanged -= new EventHandler(OnGlobalPaletteChanged);
            }

            base.Dispose(disposing);
        }
        #endregion

        #region "   Overrides & Draw  "
        protected override void OnLostFocus(EventArgs e)
        {
            _hasFocus = false;
            Invalidate();
            base.OnLostFocus(e);
        }

        protected override void OnGotFocus(EventArgs e)
        {
            _hasFocus = true;
            Invalidate();
            base.OnGotFocus(e);
        }

        // Selects a node that is clicked on its label or tag text.
        protected override void OnMouseDown(MouseEventArgs e)
        {
            TreeNode clickedNode = this.GetNodeAt(e.X, e.Y);
            if (clickedNode == null)
                return;
            if (NodeBounds(clickedNode).Contains(e.X, e.Y))
            {
                this.SelectedNode = clickedNode;
            }
        }

        //create Graphics Path
        private GraphicsPath CreateRectGraphicsPath(Rectangle rect)
        {
            GraphicsPath path = new GraphicsPath();
            path.AddRectangle(rect);
            return path;
        }

        private PaletteState GetNodeState(DrawTreeNodeEventArgs e)
        {
            // Find the correct state when getting button values
            if (!Enabled)
                return PaletteState.Disabled;
            else
            {
                if (e.State == TreeNodeStates.Hot)
                    return PaletteState.Tracking;
                else
                    return PaletteState.Pressed;
            }
        }

        // Draws a node.
        protected override void OnDrawNode(DrawTreeNodeEventArgs e)
        {
            e.DrawDefault = false;
            Graphics g = e.Graphics;

            // Get the renderer associated with this palette
            IRenderer renderer = _palette.GetRenderer();

            // We want to anti alias the drawing for nice smooth curves
            g.SmoothingMode = SmoothingMode.AntiAlias;
            g.CompositingQuality = CompositingQuality.HighQuality;
            g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit;

            // Create the rendering context that is passed into all renderer calls
            using (RenderContext renderContext = new RenderContext(this, g, NodeBounds(e.Node), renderer))
            {

                // we need to find the correct palette state based on if the mouse
                // is over the control if the mouse button is pressed down or not.
                PaletteState buttonState = PaletteState.CheckedPressed;

                // Create a rectangle inset, this is where we will draw the node
                Rectangle innerRect = NodeBounds(e.Node);
                Rectangle innerContent = new Rectangle(innerRect.X + 1, innerRect.Y + 1, innerRect.Width - 2, innerRect.Height - 2);

                // Set the style of control we want to draw
                _paletteBack.Style = PaletteBackStyle.ButtonListItem;
                _paletteBorder.Style = PaletteBorderStyle.ButtonListItem;
                _paletteContent.Style = PaletteContentStyle.ButtonListItem;

                // Get the color and font used to draw the text
                Color textColor = _palette.GetContentShortTextColor1(PaletteContentStyle.ButtonListItem, buttonState);
                Font textFont = _palette.GetContentShortTextFont(PaletteContentStyle.ButtonListItem, buttonState);

                //do we have enought room for the text? --> let expand it
                SizeF TextLenght = g.MeasureString(e.Node.Text, textFont);
                innerRect.Width = (int)TextLenght.Width;
                innerContent.Width = (int)TextLenght.Width - 2;

                //clear contents
                g.FillRectangle(new SolidBrush(this.BackColor), innerRect.X - 1, innerRect.Y, innerRect.Width + 2, innerRect.Height);


                //draw only for some node states
                if (e.State == TreeNodeStates.Hot || e.State == TreeNodeStates.Selected || (e.State & TreeNodeStates.Focused) != 0)
                {
                    //get button state
                    buttonState = GetNodeState(e);

                    //lost focus
                    if (!_hasFocus & !(buttonState == PaletteState.Tracking)) buttonState = PaletteState.Normal;

                    //force disabled mode
                    if (this.Enabled == false) buttonState = PaletteState.Disabled;

                    //////////////////////////////////////////////////////////////////////////////////
                    // In case the border has a rounded effect we need to get the background path   //
                    // to draw from the border part of the renderer. It will return a path that is  //
                    // appropriate for use drawing within the border settings.                      //
                    //////////////////////////////////////////////////////////////////////////////////

                    // Get the color and font used to draw the text
                    textColor = _palette.GetContentShortTextColor1(PaletteContentStyle.ButtonListItem, buttonState);

                    using (GraphicsPath path = renderer.RenderStandardBorder.GetBackPath(renderContext, innerRect, _paletteBorder, VisualOrientation.Top, buttonState))
                    {
                        // Ask renderer to draw the background
                        _mementoBack2 = renderer.RenderStandardBack.DrawBack(renderContext, innerContent, path, _paletteBack, VisualOrientation.Top, buttonState, _mementoBack2);
                    }

                    // Now we draw the border of the inner area, also in ButtonListItem style
                    renderer.RenderStandardBorder.DrawBorder(renderContext, innerRect, _paletteBorder, VisualOrientation.Bottom, buttonState);

                    // Draw the node text.
                    using (Brush textBrush = new SolidBrush(textColor))
                    {
                        // We want to anti alias the drawing for nice smooth curves
                        g.DrawString(e.Node.Text, textFont, textBrush, e.Bounds.Left, e.Bounds.Top);
                    }
                }
                else
                {
                    // Get the color and font used to draw the text
                    try
                    {
                        textColor = _palette.ColorTable.MenuItemText;
                        //textColor = _palette.GetContentShortTextColor1(PaletteContentStyle.LabelNormalControl, buttonState);
                    }
                    catch (Exception ex)
                    {
                        Debug.WriteLine(ex.Message);
                        textColor = this.ForeColor;
                    }
                    // Draw the node text.
                    using (Brush textBrush = new SolidBrush(textColor))
                        g.DrawString(e.Node.Text, textFont, textBrush, e.Bounds.Left, e.Bounds.Top);
                }
            }
        }

        // Returns the bounds of the specified node, including the region
        // occupied by the node label and any node tag displayed.
        private Rectangle NodeBounds(TreeNode node)
        {

            // Set the return value to the normal node bounds.
            Rectangle bounds = node.Bounds;
            return bounds;
        }
        #endregion
    }
}


VB
Code: Select all
Imports System.Collections
Imports System.Collections.Generic
Imports System.Data
Imports System.Diagnostics
Imports ComponentFactory.Krypton.Toolkit
Imports System.Drawing
Imports System.Drawing.Drawing2D
Imports System.Windows.Forms

<System.Drawing.ToolboxBitmapAttribute(GetType(System.Windows.Forms.TreeView))> _
Public Class KryptonTreeView
  Inherits TreeView

#Region "   Members   "
  Private _hasFocus As Boolean = False
  Private _palette As IPalette
  Private _paletteRedirect As PaletteRedirect
  Private _paletteBack As PaletteBackInheritRedirect
  Private _paletteBorder As PaletteBorderInheritRedirect
  Private _paletteContent As PaletteContentInheritRedirect
  Private _mementoContent As IDisposable
  Private _mementoBack1 As IDisposable
  Private _mementoBack2 As IDisposable
#End Region

#Region "   Ctor   "
  Public Sub New()
    'double buffer
    SetStyle(ControlStyles.OptimizedDoubleBuffer Or ControlStyles.AllPaintingInWmPaint, True)
    UpdateStyles()

    ' Configure the TreeView control for owner-draw.
    Me.DrawMode = TreeViewDrawMode.OwnerDrawText

    ' add Palette Handler
    ' Cache the current global palette setting
    _palette = KryptonManager.CurrentGlobalPalette

    ' Hook into palette events
    If _palette IsNot Nothing Then
      AddHandler _palette.PalettePaint, AddressOf OnPalettePaint
    End If

    ' We want to be notified whenever the global palette changes
    AddHandler KryptonManager.GlobalPaletteChanged, AddressOf OnGlobalPaletteChanged

    ' Create redirection object to the base palette
    _paletteRedirect = New PaletteRedirect(_palette)

    ' Create accessor objects for the back, border and content
    _paletteBack = New PaletteBackInheritRedirect(_paletteRedirect)
    _paletteBorder = New PaletteBorderInheritRedirect(_paletteRedirect)

    _paletteContent = New PaletteContentInheritRedirect(_paletteRedirect)
  End Sub
#End Region

#Region "   Palette Change Event & Dispose   "
  'Krypton Palette Events
  Private Sub OnGlobalPaletteChanged(ByVal sender As Object, ByVal e As EventArgs)
    ' Unhook events from old palette
    If _palette IsNot Nothing Then
      RemoveHandler _palette.PalettePaint, AddressOf OnPalettePaint
    End If

    ' Cache the new IPalette that is the global palette
    _palette = KryptonManager.CurrentGlobalPalette
    _paletteRedirect.Target = _palette

    ' Hook into events for the new palette
    If _palette IsNot Nothing Then
      AddHandler _palette.PalettePaint, AddressOf OnPalettePaint
    End If

    ' Change of palette means we should repaint to show any changes
    Invalidate()
  End Sub


  'Krypton Palette Events
  Private Sub OnPalettePaint(ByVal sender As Object, ByVal e As PaletteLayoutEventArgs)
    ' Palette indicates we might need to repaint, so lets do it
    Invalidate()
  End Sub

  'Dispose Event
  Protected Overrides Sub Dispose(ByVal disposing As Boolean)
    If disposing Then
      If _mementoContent IsNot Nothing Then
        _mementoContent.Dispose()
        _mementoContent = Nothing
      End If

      If _mementoBack1 IsNot Nothing Then
        _mementoBack1.Dispose()
        _mementoBack1 = Nothing
      End If

      If _mementoBack2 IsNot Nothing Then
        _mementoBack2.Dispose()
        _mementoBack2 = Nothing
      End If

      ' Unhook from the palette events
      If _palette IsNot Nothing Then
        RemoveHandler _palette.PalettePaint, AddressOf OnPalettePaint
        _palette = Nothing
      End If

      ' Unhook from the static events, otherwise we cannot be garbage collected
      RemoveHandler KryptonManager.GlobalPaletteChanged, AddressOf OnGlobalPaletteChanged
    End If

    MyBase.Dispose(disposing)
  End Sub
#End Region

#Region "   Overrides & Draw  "
  Protected Overrides Sub OnLostFocus(ByVal e As EventArgs)
    _hasFocus = False
    Invalidate()
    MyBase.OnLostFocus(e)
  End Sub

  Protected Overrides Sub OnGotFocus(ByVal e As EventArgs)
    _hasFocus = True
    Invalidate()
    MyBase.OnGotFocus(e)
  End Sub

  ' Selects a node that is clicked on its label or tag text.
  Protected Overrides Sub OnMouseDown(ByVal e As MouseEventArgs)
    Dim clickedNode As TreeNode = Me.GetNodeAt(e.X, e.Y)
    If clickedNode Is Nothing Then
      Return
    End If
    If NodeBounds(clickedNode).Contains(e.X, e.Y) Then
      Me.SelectedNode = clickedNode
    End If
  End Sub

  'create Graphics Path
  Private Function CreateRectGraphicsPath(ByVal rect As Rectangle) As GraphicsPath
    Dim path As New GraphicsPath()
    path.AddRectangle(rect)
    Return path
  End Function

  Private Function GetNodeState(ByVal e As DrawTreeNodeEventArgs) As PaletteState
    ' Find the correct state when getting button values
    If Not Enabled Then
      Return PaletteState.Disabled
    Else
      If e.State = TreeNodeStates.Hot Then
        Return PaletteState.Tracking
      Else
        Return PaletteState.Pressed
      End If
    End If
  End Function

  ' Draws a node.
  Protected Overrides Sub OnDrawNode(ByVal e As DrawTreeNodeEventArgs)
    e.DrawDefault = False
    Dim g As Graphics = e.Graphics

    ' Get the renderer associated with this palette
    Dim renderer As IRenderer = _palette.GetRenderer()

    ' We want to anti alias the drawing for nice smooth curves
    g.SmoothingMode = SmoothingMode.AntiAlias
    g.CompositingQuality = CompositingQuality.HighQuality
    g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit

    ' Create the rendering context that is passed into all renderer calls
    Using renderContext As New RenderContext(Me, g, NodeBounds(e.Node), renderer)

      ' we need to find the correct palette state based on if the mouse
      ' is over the control if the mouse button is pressed down or not.
      Dim buttonState As PaletteState = PaletteState.CheckedPressed

      ' Create a rectangle inset, this is where we will draw the node
      Dim innerRect As Rectangle = NodeBounds(e.Node)
      Dim innerContent As New Rectangle(innerRect.X + 1, innerRect.Y + 1, innerRect.Width - 2, innerRect.Height - 2)

      ' Set the style of control we want to draw
      _paletteBack.Style = PaletteBackStyle.ButtonListItem
      _paletteBorder.Style = PaletteBorderStyle.ButtonListItem
      _paletteContent.Style = PaletteContentStyle.ButtonListItem

      ' Get the color and font used to draw the text
      Dim textColor As Color = _palette.GetContentShortTextColor1(PaletteContentStyle.ButtonListItem, buttonState)
      Dim textFont As Font = _palette.GetContentShortTextFont(PaletteContentStyle.ButtonListItem, buttonState)

      'do we have enought room for the text? --> let expand it
      Dim TextLenght As SizeF = g.MeasureString(e.Node.Text, textFont)
      innerRect.Width = CInt(Math.Truncate(TextLenght.Width))
      innerContent.Width = CInt(Math.Truncate(TextLenght.Width)) - 2

      'clear contents
      g.FillRectangle(New SolidBrush(Me.BackColor), innerRect.X - 1, innerRect.Y, innerRect.Width + 2, innerRect.Height)


      'draw only for some node states
      If e.State = TreeNodeStates.Hot OrElse e.State = TreeNodeStates.Selected OrElse (e.State And TreeNodeStates.Focused) <> 0 Then
        'get button state
        buttonState = GetNodeState(e)

        'lost focus
        If Not _hasFocus And Not buttonState = PaletteState.Tracking Then
          buttonState = PaletteState.Normal
        End If

        'force disabled mode
        If Me.Enabled = False Then
          buttonState = PaletteState.Disabled
        End If

        '''///////////////////////////////////////////////////////////////////////////////
        ' In case the border has a rounded effect we need to get the background path   //
        ' to draw from the border part of the renderer. It will return a path that is  //
        ' appropriate for use drawing within the border settings.                      //
        '''///////////////////////////////////////////////////////////////////////////////

        ' Get the color and font used to draw the text
        textColor = _palette.GetContentShortTextColor1(PaletteContentStyle.ButtonListItem, buttonState)

        Using path As GraphicsPath = renderer.RenderStandardBorder.GetBackPath(renderContext, innerRect, _paletteBorder, VisualOrientation.Top, buttonState)
          ' Ask renderer to draw the background
          _mementoBack2 = renderer.RenderStandardBack.DrawBack(renderContext, innerContent, path, _paletteBack, VisualOrientation.Top, buttonState, _
           _mementoBack2)
        End Using

        ' Now we draw the border of the inner area, also in ButtonListItem style
        renderer.RenderStandardBorder.DrawBorder(renderContext, innerRect, _paletteBorder, VisualOrientation.Bottom, buttonState)

        ' Draw the node text.
        Using textBrush As Brush = New SolidBrush(textColor)
          ' We want to anti alias the drawing for nice smooth curves
          g.DrawString(e.Node.Text, textFont, textBrush, e.Bounds.Left, e.Bounds.Top)
        End Using
      Else
        ' Get the color and font used to draw the text
        Try
          'textColor = _palette.GetContentShortTextColor1(PaletteContentStyle.LabelNormalControl, buttonState);
          textColor = _palette.ColorTable.MenuItemText
        Catch ex As Exception
          Debug.WriteLine(ex.Message)
          textColor = Me.ForeColor
        End Try
        ' Draw the node text.
        Using textBrush As Brush = New SolidBrush(textColor)
          g.DrawString(e.Node.Text, textFont, textBrush, e.Bounds.Left, e.Bounds.Top)
        End Using
      End If
    End Using
  End Sub

  ' Returns the bounds of the specified node, including the region
  ' occupied by the node label and any node tag displayed.
  Private Function NodeBounds(ByVal node As TreeNode) As Rectangle

    ' Set the return value to the normal node bounds.
    Dim bounds As Rectangle = node.Bounds
    Return bounds
  End Function
#End Region
End Class
Nick71
 
Posts: 18
Joined: Fri Jan 15, 2010 11:52 pm
Location: Scotland, UK

Re: Down and dirty KryptonTreeView

Postby quimbo » Thu Mar 10, 2011 2:21 am

I created a treeview based on the code. The selected item always has a blue bar at the end of the selected text.

Image

Any idea of what can be causing this?
quimbo
 
Posts: 169
Joined: Sat Sep 08, 2007 3:38 am

Re: Down and dirty KryptonTreeView

Postby Angel » Thu Mar 10, 2011 6:35 pm

have you changed the default font for the palette?
Regards /// Angel
Angel
 
Posts: 251
Joined: Tue Aug 07, 2007 5:12 pm
Location: Lugano, Switzerland

Re: Down and dirty KryptonTreeView

Postby quimbo » Thu Mar 10, 2011 11:28 pm

I had this line of code I used for the treeveiw in the AC toolkit:

uxTreeView.Font = DirectCast(ParentForm, MainForm).KryptonManager1.GlobalPalette.GetContentLongTextFont(PaletteContentStyle.LabelNormalControl, PaletteState.Normal)

commenting it out fixed the issue.

Thank you....
quimbo
 
Posts: 169
Joined: Sat Sep 08, 2007 3:38 am

Re: Down and dirty KryptonTreeView

Postby javierJJJ » Fri Apr 29, 2011 6:25 pm

I changed some code for fix a problems with node painting
Fixed the problem of node painting and nodes painting in
the top-left corner that are not visibles (children)

Code: Select all
Imports System.Collections
Imports System.Collections.Generic
Imports System.Data
Imports System.Diagnostics
Imports ComponentFactory.Krypton.Toolkit
Imports System.Drawing
Imports System.Drawing.Drawing2D
Imports System.Windows.Forms

    <System.Drawing.ToolboxBitmapAttribute(GetType(System.Windows.Forms.TreeView))> _
    Public Class KryptonTreeView
        Inherits TreeView

#Region "   Members   "
        Private _hasFocus As Boolean = False
        Private _palette As IPalette
        Private _paletteRedirect As PaletteRedirect
        Private _paletteBack As PaletteBackInheritRedirect
        Private _paletteBorder As PaletteBorderInheritRedirect
        Private _paletteContent As PaletteContentInheritRedirect
        Private _mementoContent As IDisposable
        Private _mementoBack1 As IDisposable
        Private _mementoBack2 As IDisposable
#End Region

#Region "   Ctor   "
        Public Sub New()
            'double buffer
            SetStyle(ControlStyles.OptimizedDoubleBuffer Or ControlStyles.AllPaintingInWmPaint, True)
            UpdateStyles()

            ' Configure the TreeView control for owner-draw.
            Me.DrawMode = TreeViewDrawMode.OwnerDrawText

            ' add Palette Handler
            ' Cache the current global palette setting
            _palette = KryptonManager.CurrentGlobalPalette

            ' Hook into palette events
            If _palette IsNot Nothing Then
                AddHandler _palette.PalettePaint, AddressOf OnPalettePaint
            End If

            ' We want to be notified whenever the global palette changes
            AddHandler KryptonManager.GlobalPaletteChanged, AddressOf OnGlobalPaletteChanged

            ' Create redirection object to the base palette
            _paletteRedirect = New PaletteRedirect(_palette)

            ' Create accessor objects for the back, border and content
            _paletteBack = New PaletteBackInheritRedirect(_paletteRedirect)
            _paletteBorder = New PaletteBorderInheritRedirect(_paletteRedirect)

            _paletteContent = New PaletteContentInheritRedirect(_paletteRedirect)
        End Sub
#End Region

#Region "   Palette Change Event & Dispose   "
        'Krypton Palette Events
        Private Sub OnGlobalPaletteChanged(ByVal sender As Object, ByVal e As EventArgs)
            ' Unhook events from old palette
            If _palette IsNot Nothing Then
                RemoveHandler _palette.PalettePaint, AddressOf OnPalettePaint
            End If

            ' Cache the new IPalette that is the global palette
            _palette = KryptonManager.CurrentGlobalPalette
            _paletteRedirect.Target = _palette

            'Implements the size of node with the font of palette
            Dim textFont As Font = _palette.GetContentShortTextFont(PaletteContentStyle.ButtonStandalone, PaletteState.Normal)
            Me.Font = textFont

            ' Hook into events for the new palette
            If _palette IsNot Nothing Then
                AddHandler _palette.PalettePaint, AddressOf OnPalettePaint
            End If

            ' Change of palette means we should repaint to show any changes
            Invalidate()
        End Sub


        'Kripton Palette Events
        Private Sub OnPalettePaint(ByVal sender As Object, ByVal e As PaletteLayoutEventArgs)
            ' Palette indicates we might need to repaint, so lets do it
            Invalidate()
        End Sub

        'Dispose Event
        Protected Overrides Sub Dispose(ByVal disposing As Boolean)
            If disposing Then
                If _mementoContent IsNot Nothing Then
                    _mementoContent.Dispose()
                    _mementoContent = Nothing
                End If

                If _mementoBack1 IsNot Nothing Then
                    _mementoBack1.Dispose()
                    _mementoBack1 = Nothing
                End If

                If _mementoBack2 IsNot Nothing Then
                    _mementoBack2.Dispose()
                    _mementoBack2 = Nothing
                End If

                ' Unhook from the palette events
                If _palette IsNot Nothing Then
                    RemoveHandler _palette.PalettePaint, AddressOf OnPalettePaint
                    _palette = Nothing
                End If

                ' Unhook from the static events, otherwise we cannot be garbage collected
                AddHandler KryptonManager.GlobalPaletteChanged, AddressOf OnGlobalPaletteChanged
            End If

            MyBase.Dispose(disposing)
        End Sub
#End Region

#Region "   Overrides & Draw  "
        Protected Overrides Sub OnLostFocus(ByVal e As EventArgs)
            _hasFocus = False
            Invalidate()
            MyBase.OnLostFocus(e)
        End Sub

        Protected Overrides Sub OnGotFocus(ByVal e As EventArgs)
            _hasFocus = True
            Invalidate()
            MyBase.OnGotFocus(e)
        End Sub

        ' Selects a node that is clicked on its label or tag text.
        Protected Overrides Sub OnMouseDown(ByVal e As MouseEventArgs)
            Dim clickedNode As TreeNode = Me.GetNodeAt(e.X, e.Y)
            If clickedNode Is Nothing Then
                Return
            End If
            If NodeBounds(clickedNode).Contains(e.X, e.Y) Then
                Me.SelectedNode = clickedNode
            End If
        End Sub

        'create Graphics Path
        Private Function CreateRectGraphicsPath(ByVal rect As Rectangle) As GraphicsPath
            Dim path As New GraphicsPath()
            path.AddRectangle(rect)
            Return path
        End Function

        Private Function GetNodeState(ByVal e As DrawTreeNodeEventArgs) As PaletteState
            ' Find the correct state when getting button values
            If Not Enabled Then
                Return PaletteState.Disabled
            Else
                If e.State = TreeNodeStates.Hot Then
                    Return PaletteState.Tracking
                Else
                    Return PaletteState.Pressed
                End If
            End If
        End Function

        ' Draws a node.
        Protected Overrides Sub OnDrawNode(ByVal e As DrawTreeNodeEventArgs)
            If e.Node.IsVisible = False Then Return

            e.DrawDefault = False
            Dim g As Graphics = e.Graphics

            ' Get the renderer associated with this palette
            Dim renderer As IRenderer = _palette.GetRenderer()

            ' We want to anti alias the drawing for nice smooth curves
            g.SmoothingMode = SmoothingMode.AntiAlias
            g.CompositingQuality = CompositingQuality.HighQuality
            g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit

            ' Create the rendering context that is passed into all renderer calls
            Using renderContext As New RenderContext(Me, g, NodeBounds(e.Node), renderer)

                ' we need to find the correct palette state based on if the mouse
                ' is over the control if the mouse button is pressed down or not.
                Dim buttonState As PaletteState = PaletteState.CheckedPressed

                ' Create a rectangle inset, this is where we will draw the node
                Dim innerRect As Rectangle = NodeBounds(e.Node)
                Dim innerContent As New Rectangle(innerRect.X + 1, innerRect.Y + 1, innerRect.Width - 2, innerRect.Height - 2)

                ' Set the style of control we want to draw
                _paletteBack.Style = PaletteBackStyle.ButtonStandalone
                _paletteBorder.Style = PaletteBorderStyle.ButtonStandalone
                _paletteContent.Style = PaletteContentStyle.ButtonStandalone

                ' Get the color and font used to draw the text
                Dim textColor As Color = _palette.GetContentShortTextColor1(PaletteContentStyle.ButtonStandalone, buttonState)
                Dim textFont As Font = _palette.GetContentShortTextFont(PaletteContentStyle.ButtonStandalone, buttonState)

                'do we have enought room for the text? --> let expand it
                Dim TextLenght As SizeF = g.MeasureString(e.Node.Text, textFont)
                innerRect.Width = Math.Max(innerRect.Width, Math.Round(TextLenght.Width))
                innerContent.Width = innerRect.Width - 2

                'clear contents
                g.FillRectangle(New SolidBrush(Me.BackColor), innerRect.X - 1, innerRect.Y, innerRect.Width + 2, innerRect.Height)
                If e.State = TreeNodeStates.Hot Then
                    Stop
                End If
                'draw only for some node states
                If e.State = TreeNodeStates.Hot OrElse e.State = TreeNodeStates.Selected OrElse (e.State And TreeNodeStates.Focused) <> 0 Then
                    'get button state
                    buttonState = GetNodeState(e)

                    'lost focus
                    If Not _hasFocus Then
                        buttonState = PaletteState.Normal
                    End If

                    'force disabled mode
                    If Me.Enabled = False Then
                        buttonState = PaletteState.Disabled
                    End If

                    '''///////////////////////////////////////////////////////////////////////////////
                    ' In case the border has a rounded effect we need to get the background path   //
                    ' to draw from the border part of the renderer. It will return a path that is  //
                    ' appropriate for use drawing within the border settings.                      //
                    '''///////////////////////////////////////////////////////////////////////////////

                    ' Get the color and font used to draw the text
                    textColor = _palette.GetContentShortTextColor1(PaletteContentStyle.ButtonStandalone, buttonState)

                    Using path As GraphicsPath = renderer.RenderStandardBorder.GetBackPath(renderContext, innerRect, _paletteBorder, VisualOrientation.Top, buttonState)
                        ' Ask renderer to draw the background
                        _mementoBack2 = renderer.RenderStandardBack.DrawBack(renderContext, innerContent, path, _paletteBack, VisualOrientation.Top, buttonState, _
                         _mementoBack2)
                    End Using

                    ' Now we draw the border of the inner area, also in ButtonStandalone style
                    renderer.RenderStandardBorder.DrawBorder(renderContext, innerRect, _paletteBorder, VisualOrientation.Bottom, buttonState)

                    ' Draw the node text.
                    Using textBrush As Brush = New SolidBrush(textColor)
                        ' We want to anti alias the drawing for nice smooth curves
                        g.DrawString(e.Node.Text, textFont, textBrush, e.Node.Bounds.Left, e.Node.Bounds.Top)
                    End Using
                Else
                    ' Get the color and font used to draw the text
                    Try
                        'textColor = _palette.GetContentShortTextColor1(PaletteContentStyle.LabelNormalControl, buttonState);
                        textColor = _palette.ColorTable.MenuItemText
                    Catch ex As Exception
                        Debug.WriteLine(ex.Message)
                        textColor = Me.ForeColor
                    End Try
                    ' Draw the node text.
                    Using textBrush As Brush = New SolidBrush(textColor)
                        g.DrawString(e.Node.Text, textFont, textBrush, e.Node.Bounds.Left, e.Node.Bounds.Top)
                    End Using
                End If
            End Using
        End Sub

        ' Returns the bounds of the specified node, including the region
        ' occupied by the node label and any node tag displayed.
        Private Function NodeBounds(ByVal node As TreeNode) As Rectangle

            ' Set the return value to the normal node bounds.
            Dim bounds As Rectangle = node.Bounds
            Return bounds
        End Function
#End Region
    End Class
javierJJJ
 
Posts: 34
Joined: Wed Nov 04, 2009 6:02 pm


Return to Code Snippets

Who is online

Users browsing this forum: No registered users and 1 guest

cron