C#: TreeView owner drawing with ownerdrawtext and the weird black highlighting when clicking on a node

前端 未结 1 896
清歌不尽
清歌不尽 2020-12-01 14:54

I set the DrawMode to OwnerDrawText and tacked on to the DrawNode event, added my code to draw the text the way I want and all works well save for some odd black selection h

相关标签:
1条回答
  • 2020-12-01 15:57

    In my experience you usually can't. Either you draw the item yourself or you don't. If you try to composite your graphics on top of those drawn by the control, you'll end up with glitches.

    It is a bit of a pain because you have to handle focus rectangles, selection highlights, and drawing all the glyphs yourself.

    On the plus side, Visual Styles can be used to do most of the work.

    Here's some code that will get you most of the way there (it's incomplete, in that it uses some methods not included, and it doesn't render exactly what a normal treeview does because it supports grad filled items and columns, but should be a handy reference)

        protected virtual void OnDrawTreeNode(object sender, DrawTreeNodeEventArgs e)
        {
            string text = e.Node.Text;
            Rectangle itemRect = e.Bounds;
            if (e.Bounds.Height < 1 || e.Bounds.Width < 1)
                return;
    
            int cIndentBy   = 19;       // TODO - support Indent value
            int cMargin     = 6;        // TODO - this is a bit random, it's slaved off the Indent in some way
            int cTwoMargins = cMargin * 2;
    
            int indent = (e.Node.Level * cIndentBy) + cMargin;
            int iconLeft = indent;                      // Where to draw parentage lines & icon/checkbox
            int textLeft = iconLeft + 16;               // Where to draw text
    
            Color leftColour = e.Node.BackColor;
            Color textColour = e.Node.ForeColor;
    
            if (Bitfield.IsBitSet(e.State, TreeNodeStates.Grayed))
                textColour = Color.FromArgb(255,128,128,128);
    
            // Grad-fill the background
            Brush backBrush = new SolidBrush(leftColour);
            e.Graphics.FillRectangle(backBrush, itemRect);
    
            // Faint underline along the bottom of each item
            Color separatorColor = ColourUtils.Mix(leftColour, Color.FromArgb(255,0,0,0), 0.02);
            Pen separatorPen = new Pen(separatorColor);
            e.Graphics.DrawLine(separatorPen, itemRect.Left, itemRect.Bottom-1, itemRect.Right, itemRect.Bottom-1);
    
            // Bodged to use Button styles as Treeview styles not available on my laptop...
            if (!HideSelection)
            {
                if (Bitfield.IsBitSet(e.State, TreeNodeStates.Selected) || Bitfield.IsBitSet(e.State, TreeNodeStates.Hot))
                {
                    Rectangle selRect = new Rectangle(textLeft, itemRect.Top, itemRect.Right - textLeft, itemRect.Height);
                    VisualStyleRenderer renderer = new VisualStyleRenderer((ContainsFocus) ? VisualStyleElement.Button.PushButton.Hot
                                                                                           : VisualStyleElement.Button.PushButton.Normal);
                    renderer.DrawBackground(e.Graphics, selRect);
    
                    // Bodge to make VisualStyle look like Explorer selections - overdraw with alpha'd white rectangle to fade the colour a lot
                    Brush bodge = new SolidBrush(Color.FromArgb((Bitfield.IsBitSet(e.State, TreeNodeStates.Hot)) ? 224 : 128,255,255,255));
                    e.Graphics.FillRectangle(bodge, selRect);
                }
            }
    
            Pen dotPen = new Pen(Color.FromArgb(128,128,128));
            dotPen.DashStyle = DashStyle.Dot;
    
            int midY = (itemRect.Top + itemRect.Bottom) / 2;
    
            // Draw parentage lines
            if (ShowLines)
            {
                int x    = cMargin * 2;
    
                if (e.Node.Level == 0 && e.Node.PrevNode == null)
                {
                    // The very first node in the tree has a half-height line
                    e.Graphics.DrawLine(dotPen, x, midY, x, itemRect.Bottom);
                }
                else
                {
                    TreeNode testNode = e.Node;         // Used to only draw lines to nodes with Next Siblings, as in normal TreeViews
                    for (int iLine = e.Node.Level; iLine >= 0; iLine--)
                    {
                        if (testNode.NextNode != null)
                        {
                            x = (iLine * cIndentBy) + (cMargin * 2);
                            e.Graphics.DrawLine(dotPen, x, itemRect.Top, x, itemRect.Bottom);
                        }
    
                        testNode = testNode.Parent;
                    }
    
                    x = (e.Node.Level * cIndentBy) + cTwoMargins;
                    e.Graphics.DrawLine(dotPen,  x, itemRect.Top, x, midY);
                }
    
                e.Graphics.DrawLine(dotPen, iconLeft + cMargin, midY, iconLeft + cMargin + 10, midY);
            }
    
            // Draw Expand (plus/minus) icon if required
            if (ShowPlusMinus && e.Node.Nodes.Count > 0)
            {
                // Use the VisualStyles renderer to use the proper OS-defined glyphs
                Rectangle expandRect = new Rectangle(iconLeft-1, midY - 7, 16, 16);
    
                VisualStyleElement element = (e.Node.IsExpanded) ? VisualStyleElement.TreeView.Glyph.Opened
                                                                 : VisualStyleElement.TreeView.Glyph.Closed;
    
                VisualStyleRenderer renderer = new VisualStyleRenderer(element);
                renderer.DrawBackground(e.Graphics, expandRect);
            }
    
            // Draw the text, which is separated into columns by | characters
            Point textStartPos = new Point(itemRect.Left + textLeft, itemRect.Top);
            Point textPos = new Point(textStartPos.X, textStartPos.Y);
    
            Font textFont = e.Node.NodeFont;    // Get the font for the item, or failing that, for this control
            if (textFont == null)
                textFont = Font;
    
            StringFormat drawFormat = new StringFormat();
            drawFormat.Alignment = StringAlignment.Near;
            drawFormat.LineAlignment = StringAlignment.Center;
            drawFormat.FormatFlags = StringFormatFlags.NoWrap;
    
            string [] columnTextList = text.Split('|');
            for (int iCol = 0; iCol < columnTextList.GetLength(0); iCol++)
            {
                Rectangle textRect = new Rectangle(textPos.X, textPos.Y, itemRect.Right - textPos.X, itemRect.Bottom - textPos.Y);
                if (mColumnImageList != null && mColumnImageList[iCol] != null)
                {
                    // This column has an imagelist assigned, so we use the column text as an integer zero-based index
                    // into the imagelist to indicate the icon to display
                    int iImage = 0;
                    try
                    {
                        iImage = MathUtils.Clamp(Convert.ToInt32(columnTextList[iCol]), 0, mColumnImageList[iCol].Images.Count);
                    }
                    catch(Exception)
                    {
                        iImage = 0;
                    }
    
                    e.Graphics.DrawImageUnscaled(mColumnImageList[iCol].Images[iImage], textRect.Left, textRect.Top);
                }
                else
                    e.Graphics.DrawString(columnTextList[iCol], textFont, new SolidBrush(textColour), textRect, drawFormat);
    
                textPos.X += mColumnWidthList[iCol];
            }
    
            // Draw Focussing box around the text
            if (e.State == TreeNodeStates.Focused)
            {
                SizeF size = e.Graphics.MeasureString(text, textFont);
                size.Width = (ClientRectangle.Width - 2) - textStartPos.X;
                size.Height += 1;
                Rectangle rect = new Rectangle(textStartPos, size.ToSize());
                e.Graphics.DrawRectangle(dotPen, rect);
    //          ControlPaint.DrawFocusRectangle(e.Graphics, Rect);
            }
        }
    
    0 讨论(0)
提交回复
热议问题