首页 > 解决方案 > 在 C# 中构造一个带有文本的 3 色按钮

问题描述

我正在尝试扩展 C# Button 类,以便我可以根据提供的百分比为按钮着色,最多 3 种颜色。除了未显示按钮文本外,它似乎也可以工作。请有人建议如何显示文本?另外,我不确定 Refresh() 是否是在 Setter 方法中调用以使用提供的新百分比触发重绘的正确方法?非常感谢。

class TriColorsButton : Button
{

    private double percentOfLeftColor, percentOfRightColor;

    public TriColorsButton(String text, double percentOfLeftColor, double percentOfRightColor)
    {
        this.Text = text;
        this.percentOfLeftColor = percentOfLeftColor;
        this.percentOfRightColor = percentOfRightColor;
    }


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

        Brush brush;
        RectangleF rectFirst, rectSecond, rectThird;
        Color c1, c2, c3;
        // create the first rectangle
        rectFirst = new RectangleF(0, 0, this.Width, this.Height);
        // create the second rectangle
        int callWidth = (int)(this.Width * (100 - percentOfRightColor) / 100);
        rectSecond = new RectangleF(0, 0, callWidth, this.Height);
        // create the third rectangle
        int leftWidth = (int)(this.Width * percentOfLeftColor / 100);
        rectThird = new RectangleF(0, 0, leftWidth, this.Height);

        // create the colors
        c1 = Constants.altFoldColor;
        c2 = Constants.altCallColor;
        c3 = Constants.altRaiseColor;

        // create the brush
        brush = new SolidBrush(c1);
        // fill the segment
        pe.Graphics.FillRectangle(brush, rectFirst);
        // create the brush
        brush = new SolidBrush(c2);
        // fill the segment
        pe.Graphics.FillRectangle(brush, rectSecond);
        // create the brush
        brush = new SolidBrush(c3);
        // fill the segment
        pe.Graphics.FillRectangle(brush, rectThird);

        // dispose of the brush
        brush.Dispose();

    }

    public void SetPercentOfLeftColor(double percentOfLeftColor)
    {
        this.percentOfLeftColor = percentOfLeftColor;
        Refresh();
    }

    public double GetPercentOfLeftColor()
    {
        return percentOfLeftColor;
    }

    public void SetPercentOfRightColor(double percentOfRightColor)
    {
        this.percentOfRightColor = percentOfRightColor;
        Refresh();
    }

    public double GetPercentOfRightColor()
    {
        return percentOfRightColor;
    }

}

此外,虽然这绘制了我想要的颜色,但我失去了标准按钮的原始外观和感觉。我想保留标准按钮的外观和感觉,例如标准按钮的悬停突出显示和边框。我怎样才能做到这一点?

编辑:根据建议,我尝试为按钮绘制背景图像。这产生了一种奇怪的效果,导致我的大部分身体都变白了。如果我在屏幕上移动表单,它会重绘并看起来更好,但其他更新不会适当地发生。这是我尝试过的:

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

            Image bmp = new Bitmap(Width, Height);
            using (Graphics g = Graphics.FromImage(bmp))
            {
                Brush brush;
                RectangleF rectFirst, rectSecond, rectThird;
                Color c1, c2, c3;
                // create the first rectangle
                rectFirst = new RectangleF(0, 0, this.Width, this.Height);
                // create the second rectangle
                int callWidth = (int)(this.Width * (100 - percentOfRightColor) / 100);
                rectSecond = new RectangleF(0, 0, callWidth, this.Height);
                // create the third rectangle
                int leftWidth = (int)(this.Width * percentOfLeftColor / 100);
                rectThird = new RectangleF(0, 0, leftWidth, this.Height);

                // create the colors
                c1 = Constants.altFoldColor;
                c2 = Constants.altCallColor;
                c3 = Constants.altRaiseColor;
                // create the brush
                brush = new SolidBrush(c1);
                // fill the segment
                g.FillRectangle(brush, rectFirst);
                // create the brush
                brush = new SolidBrush(c2);
                // fill the segment
                g.FillRectangle(brush, rectSecond);
                // create the brush
                brush = new SolidBrush(c3);
                // fill the segment
                g.FillRectangle(brush, rectThird);

                // dispose of the brush
                brush.Dispose();
            }
            this.BackgroundImage = bmp;
            
        }

EDIT2:我想出了如何实现我想要的。我添加了一个绘制和设置背景的方法,并从构造函数中调用它。OnPaint 方法不再需要覆盖:

private void SetBackgroundImage()
        {
            Image bmp = new Bitmap(Width, Height);
            using (Graphics g = Graphics.FromImage(bmp))
            {
                Brush brush;
                RectangleF rectFirst, rectSecond, rectThird;
                Color c1, c2, c3;
                // create the first rectangle
                rectFirst = new RectangleF(0, 0, this.Width, this.Height);
                // create the second rectangle
                int callWidth = (int)(this.Width * (100 - percentOfRightColor) / 100);
                rectSecond = new RectangleF(0, 0, callWidth, this.Height);
                // create the third rectangle
                int leftWidth = (int)(this.Width * percentOfLeftColor / 100);
                rectThird = new RectangleF(0, 0, leftWidth, this.Height);

                // create the colors
                c1 = Constants.altFoldColor;
                c2 = Constants.altCallColor;
                c3 = Constants.altRaiseColor;
                // create the brush
                brush = new SolidBrush(c1);
                // fill the segment
                g.FillRectangle(brush, rectFirst);
                // create the brush
                brush = new SolidBrush(c2);
                // fill the segment
                g.FillRectangle(brush, rectSecond);
                // create the brush
                brush = new SolidBrush(c3);
                // fill the segment
                g.FillRectangle(brush, rectThird);

                // dispose of the brush
                brush.Dispose();
            }
            this.BackgroundImage = bmp;
        }

标签: c#buttontextcolors

解决方案


OnPaint在 Windows 窗体中覆盖主要是全有或全无的事情。即,如果您需要自定义绘图,则需要绘制所有内容,包括文本。在这方面,WPF 稍微好一点,因为它允许更好的模块化。

这应该很容易通过在 OnPaint 方法的末尾Graphics.DrawStringTextRendered.DrawText末尾插入调用来解决,其中 TextRendered.DrawText 应该与其他控件更加一致。您可能还需要一些方法来确保足够的对比度,例如添加阴影或背景矩形。请注意,绘制的顺序与调用的顺序相同,即稍后的绘制调用将在之前的调用之上,因此base.OnPaint(pe);如果它完全透支,您的调用可能是多余的。

另外,我不确定 Refresh() 是否是在 Setter 方法中调用以使用提供的新百分比触发重绘的正确方法?

我通常使用.Invalidate(). 如果我正确理解文档,区别在于 Invalidate 稍后重绘控件,而 Refresh 立即重绘它。


推荐阅读