Changing color Of a Characters in Button

Vivek Dahiya 65 Reputation points
2023-10-28T08:56:36.98+00:00
public class DualcoloredButton : Button
{
    private string coloredText;
    private Color coloredTextColor = Color.Red;
    private bool coloredTextFound = false;

    public string ColoredText
    {
        get { return coloredText; }
        set
        {
            coloredText = value;
            UpdateColoredText();
        }
    }

    public Color ColoredTextColor
    {
        get { return coloredTextColor; }
        set
        {
            coloredTextColor = value;
            UpdateColoredText();
        }
    }

    public CustomButton()
    {
        // Subscribe to the Paint event to customize the button's appearance
        Paint += CustomButton_Paint;
    }

    private void CustomButton_Paint(object sender, PaintEventArgs e)
    {
        if (!coloredTextFound)
        {
            // Display an error message if the colored text is not found
            MessageBox.Show("Colored text not found on the button.", "Error");
        }
    }

    private void UpdateColoredText()
    {
        if (!string.IsNullOrEmpty(coloredText))
        {
            // Check if the colored text is found on the button's Text property
            int startIndex = Text.IndexOf(coloredText);
            if (startIndex != -1)
            {
                coloredTextFound = true;
                Invalidate(); // Trigger the Paint event to update the button's appearance
            }
            else
            {
                coloredTextFound = false;
            }
        }
    }

    protected override void OnPaint(PaintEventArgs pevent)
    {
        base.OnPaint(pevent);

        if (coloredTextFound)
        {
            // Draw the colored text on the button
            using (Brush brush = new SolidBrush(coloredTextColor))
            {
                pevent.Graphics.DrawString(coloredText, Font, brush, ClientRectangle);
            }
        }
    }
}



The above is the code that i am trying to create a button on which its some characters can have different color from the rest of text color . for example , if "Press me" is the text written on a button , this button would have a property which asks for the characters i want to have different colored . so if i choose "Pr" , both the pr should have the color lets say red but the rest of the "ess me" would have a different color . If not it should just gave a warning message and do nothing . How should i do that in win forms . ? Any expert .

Developer technologies | Windows Forms
Developer technologies | C#
Developer technologies | C#
An object-oriented and type-safe programming language that has its roots in the C family of languages and includes support for component-oriented programming.
0 comments No comments
{count} votes

Answer accepted by question author
  1. gekka 13,426 Reputation points MVP Volunteer Moderator
    2023-10-28T11:45:03.99+00:00

    Try using Graphics.MeasureCharacter to find the position of a character and then draw the character in each color.

    public class DualcoloredButton : Button
    {
        private int index = -1;
        private string textDefault;
        private string coloredText;
        private Color coloredTextColor = Color.Red;
    
        public DualcoloredButton()
        {
            base.Text = "";
        }
    
        public override string Text
        {
            get => "";
            set => textDefault = value;
        }
    
        public string TextDefault
        {
            get => textDefault;
            set
            {
                textDefault = value;
                UpdateColoredText();
                OnTextChanged(EventArgs.Empty);
            }
        }
    
        public string ColoredText
        {
            get { return coloredText; }
            set
            {
                coloredText = value;
                UpdateColoredText();
            }
        }
    
        public Color ColoredTextColor
        {
            get { return coloredTextColor; }
            set
            {
                coloredTextColor = value;
                UpdateColoredText();
            }
        }
    
        private void UpdateColoredText()
        {
            if (!string.IsNullOrEmpty(coloredText) && !string.IsNullOrEmpty(textDefault))
            {
                string displayText = this.TextDefault.Replace("&", "");
                string coloredText = this.coloredText.Replace("&", "");
                index = displayText.IndexOf(coloredText);
            }
            else
            {
                index = -1;
            }
            Invalidate();
    
        }
    
        protected override void OnPaint(PaintEventArgs pevent)
        {
            StringFormat sf = new StringFormat();
            sf.Alignment = StringAlignment.Center;
            sf.LineAlignment = StringAlignment.Center;
            sf.Trimming = StringTrimming.None;
            sf.FormatFlags = StringFormatFlags.NoWrap | StringFormatFlags.NoClip;
    
            base.OnPaint(pevent);
    
    
            using (Brush brushColor = new SolidBrush(coloredTextColor))
            using (Brush brushDefault = new SolidBrush(this.ForeColor))
            {
                string displayText = this.TextDefault?.Replace("&", "") ?? "";
                string coloredText = this.coloredText?.Replace("&", "") ?? "";
    
                if (string.IsNullOrWhiteSpace(displayText))
                {
                    return;
                }
    
                int index = displayText.IndexOf(coloredText);
    
                Brush[] brushes = new Brush[] { brushDefault, brushColor, brushDefault };
    
                Part partA = new Part(brushDefault, 0, index);
                Part partB = new Part(brushColor, index, coloredText.Length);
                Part partC = new Part(brushDefault, index + coloredText.Length, displayText.Length - index - coloredText.Length);
                Part[] parts = { partA, partB, partC };
    
                CharacterRange[] cranges = parts.Select(_ => _.ToCharacterRange()).ToArray();
    
                sf.SetMeasurableCharacterRanges(cranges);
    
                var ranges = pevent.Graphics.MeasureCharacterRanges(displayText, this.Font, this.ClientRectangle, sf);
    
                for (int i = 0; i < ranges.Length; i++)
                {
                    RectangleF rect = ranges[i].GetBounds(pevent.Graphics);
    
                    if (rect.Width > 0 && rect.Height > 0)
                    {
                        Part part = parts[i];
                        string text = part.SubString(displayText);
                        pevent.Graphics.DrawString(text, Font, part.Brush, rect, sf);
                    }
    
                }
    
                int indexAmp = this.textDefault.IndexOf("&");
                if (indexAmp < 0 || indexAmp == this.textDefault.Length - 1)
                {
                    return;
                }
    
                if (Control.ModifierKeys == Keys.Alt || IsShowMnemonicUnderLine)
                {
                    IsShowMnemonicUnderLine = true;
    
                    cranges = new[] { new CharacterRange(indexAmp, 1) };
                    sf.SetMeasurableCharacterRanges(cranges);
    
                    ranges = pevent.Graphics.MeasureCharacterRanges(displayText, this.Font, this.ClientRectangle, sf);
                    for (int i = 0; i < ranges.Length; i++)
                    {
                        RectangleF rect = ranges[i].GetBounds(pevent.Graphics);
    
                        if (rect.Width > 0 && rect.Height > 0)
                        {
                            pevent.Graphics.DrawLine(Pens.Black, rect.X, rect.Bottom, rect.Right, rect.Bottom);
                        }
    
                    }
                }
            }
    
        }
    
        public bool IsShowMnemonicUnderLine { get; set; }
    
        protected override bool ProcessMnemonic(char charCode)
        {
            if (textDefault != null)
            {
                int index = textDefault.IndexOf("&");
                if (0 <= index && index < textDefault.Length - 1)
                {
                    if (char.ToLower(charCode) == char.ToLower(textDefault[index + 1]))
                    {
                        PerformClick();
                        return true;
                    }
                }
            }
            return false;
        }
    
        class Part
        {
            public int Start;
            public int Length;
            public Brush Brush;
    
            public Part(Brush brush, int start, int length)
            {
                Brush = brush;
                Start = start;
                Length = length;
            }
    
            public CharacterRange ToCharacterRange()
            {
                return new CharacterRange(Start, Length);
            }
    
            public string SubString(string text)
            {
                return text.Substring(Start, Length);
            }
        }
    
    }
    

    Edit: Add Mnemonic logic

    Edit: Fix misalignment when TextDefault has Ampersand and coloredText has no Ampersand.

    Edit: Add draw underline logic


0 additional answers

Sort by: Most helpful

Your answer

Answers can be marked as 'Accepted' by the question author and 'Recommended' by moderators, which helps users know the answer solved the author's problem.