在C#中使标签文本透明化

6

我有一个带黑色BackColor的标签,我已经将ForeColor设置为透明。该标签位于大部分为蓝色的PictureBox之上,我已将其设置为其父级。
由于某种原因,本应显示为蓝色的文本却是白色的。
它似乎与窗体颜色或图片框的颜色无关。
当我使标签的BackColor透明时,它可以正常工作。
谢谢


1
当我将标签的BackColor设置为透明时,它可以正常工作。如果这样可以正常工作,那就这样做吧。 - David Arno
4
他们的意思是透明背景可以正常工作,但他们希望有透明前景。 - user2586804
我非常确定你需要自定义绘制这个前景。 - Mike Perrenoud
尝试将窗体上的透明度映射设置为未使用的颜色,然后将标签文本设置为该颜色。完全未经测试,仅是一种想法。 - Lotok
看起来winforms并不真正支持透明度,可以在这里查看一些帮助:https://dev59.com/T1nUa4cB1Zd3GeqPWwgX。 - TheKingDave
我相信这是Label类的一个“特性”。如果允许透明度,它将显示标签背景颜色中的文本(无论是否透明),你的文本将从定义上看是不可见的。 - H H
1个回答

8

我已经尝试过自定义支持透明ForeColor的Label,但只成功了一部分。它可以很好地工作在许多BackColor上,但对于相当多的其他BackColor则不能按预期工作。不过,如果你喜欢这个BackColor并能正常使用,那么也是可以接受的。这段代码涉及到Image,首先我们必须在Image上绘制字符串(使用高质量的绘图),然后我们还需要将所有文本(应该用Color.Black绘制)转换为Color.Transparent。我们还必须考虑Color.BlackBackColor之间的所有颜色,这些中间颜色(主要集中在文本曲线上)是最难解决的问题。这就是为什么有些BackColor会使它以意想不到的方式工作。如果我们有一些更好的算法来扫描所有可能的medium颜色并将它们转换为相应的透明颜色(alpha小于255),那么就可以解决这个问题。为了从源颜色转换为目标颜色,我们需要使用许多ColorMaps和一个ImageAttribute,这个属性将被用于确定如何绘制图像。事实上,我们可以读取每个源像素并绘制相应的目标像素,但这样做需要更多的代码(值得尝试)。下面是完整的CustomLabel代码:

public class CustomLabel : Label {
    public CustomLabel() {
        BackColor = base.BackColor;
        base.BackColor = Color.Transparent;
        DoubleBuffered = true;                     
    }
    Color backColor;
    int alpha;
    public new Color BackColor {
        get { return Color.FromArgb(alpha, backColor); }
        set { 
           alpha = value.A;
           backColor = Color.FromArgb(value.R, value.G, value.B);
           UpdateVisual(true);               
        }
    }        
    protected override void OnForeColorChanged(EventArgs e) {
        base.OnForeColorChanged(e);
        if (ForeColor == Color.Transparent) {
            base.BackColor = Color.Transparent;
            UpdateVisual(true);
        } else {
            base.BackColor = BackColor;
            BackgroundImage = null;
        }
    }
    Image img;        
    private void UpdateVisual(bool applyChange) {     
        img = new Bitmap(ClientSize.Width, ClientSize.Height, PixelFormat.Format32bppPArgb);
        using (Graphics g = Graphics.FromImage(img)){
            g.Clear(backColor);             
            g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias;                
            g.DrawString(Text, Font, Brushes.Black, ClientRectangle);
        }
        Bitmap bm = new Bitmap(ClientSize.Width, ClientSize.Height, PixelFormat.Format32bppPArgb);
        using (Graphics g = Graphics.FromImage(bm)) {
            g.SmoothingMode = SmoothingMode.HighSpeed;
            ImageAttributes ia = new ImageAttributes();
            List<ColorMap> cms = new List<ColorMap>();                
            for (decimal f = 0; f < 1; f += 0.001M) {
                ColorMap cm = new ColorMap();
                cm.NewColor = Color.FromArgb((int)((1 - f) * alpha), backColor);
                cm.OldColor = GetNormalBlendColor(backColor,Color.Black, f);                    
                cms.Add(cm);
            }              
            ia.SetRemapTable(cms.ToArray());                                
            g.DrawImage(img, new Point[] {Point.Empty, new Point(img.Width, 0), new Point(0,img.Height) }, new Rectangle() {Size = bm.Size}, GraphicsUnit.Pixel, ia);
        }
        img.Dispose();          
        img = bm;
        if (applyChange) BackgroundImage = img;
    }
    public Color GetNormalBlendColor(Color baseColor, Color blendColor, decimal opacity) {
        int R = Math.Min((int)((1 - opacity) * baseColor.R + blendColor.R * opacity), 255);
        int G = Math.Min((int)((1 - opacity) * baseColor.G + blendColor.G * opacity), 255);
        int B = Math.Min((int)((1 - opacity) * baseColor.B + blendColor.B * opacity), 255);                        
        return Color.FromArgb(R, G, B);
    }
    protected override void OnPaint(PaintEventArgs e) {
        if (ForeColor != Color.Transparent) {
            using (Brush brush = new SolidBrush(BackColor)) {
                e.Graphics.FillRectangle(brush, ClientRectangle);
            }
            base.OnPaint(e);
        }                        
    }      
    protected override void OnTextChanged(EventArgs e) {
        base.OnTextChanged(e);
        if(ForeColor == Color.Transparent) UpdateVisual(true);
    }
    protected override void OnFontChanged(EventArgs e) {
        base.OnFontChanged(e);
        if(ForeColor == Color.Transparent) UpdateVisual(true);
    }
    protected override void OnSizeChanged(EventArgs e) {
        base.OnSizeChanged(e);
        if (ForeColor == Color.Transparent) UpdateVisual(true);          
    }

}

输入图像描述

PS:我希望有人能找到解决方案来完善这段代码,它几乎很好用,但对于某些BackColor,文本曲线会变得明显,并且像是随机点状的曲线。最糟糕的背景色看起来是Color.Chocolate :)。

对于一些不工作的BackColor,这里是Color.Chocolate

输入图像描述


3
您的回答有点难以阅读,请对我这样的老年人减少使用反引号和加粗的内容,谢谢。 - Hans Passant
@HansPassant 抱歉,我不认为这很难阅读,使用反引号或加粗甚至会让我输入更多(这并不是每个人都想要的),我只是觉得这样更易读。 - King King
1
大多数人习惯于阅读书籍和报纸,但在我的地方看起来并不是这样的。在越南呢?我个人觉得很难看到那些被吸引注意力的字之间的文字。当然,你可以按照自己的方式去做,只是提醒一下,你可能会失去一个常见的读者(和投票者)对你的回答。 - Hans Passant
你能否添加一张图片来展示它是如何“像随机点曲线”的呢? - C.B.
@C.B. 你能自己试试吗?这很容易。 - King King
@C.B. 还按照您的要求添加了“不起作用的BackColor”的快照。 - King King

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接