【问题标题】:Reasons for why a WinForms label does not want to be transparent?WinForms 标签不想透明的原因是什么?
【发布时间】:2010-10-10 23:50:00
【问题描述】:

为什么我不能将标签的背景色设置为透明?我以前做过,但现在它只是不想......

我创建了一个新的 UserControl,向它添加了一个进度条和一个标签。当我将标签的 BackColor 设置为透明时,它仍然是灰色 =/ 这是为什么?

我想要的是将标签放在进度条的顶部,以便其文本在进度条“中”...

【问题讨论】:

  • 查看 alexander willemse 的回答。
  • 关于你的最后一句话(将文本放入进度条):Progress bars guidelines from Microsoft 说:不要将完成百分比或任何其他文本放在进度条上。此类文本无法访问,并且与使用主题不兼容。因此,如果您能找到另一种方式,它将更加兼容,并且看起来更好、更一致。请参阅上面链接的指南。

标签: c# winforms transparency


【解决方案1】:

向您的项目添加一个新类并发布如下所示的代码。建造。将新控件从工具箱顶部拖放到表单上。

using System;
using System.Windows.Forms;

public class TransparentLabel : Label {
  public TransparentLabel() {
    this.SetStyle(ControlStyles.Opaque, true);
    this.SetStyle(ControlStyles.OptimizedDoubleBuffer, false);
  }
  protected override CreateParams CreateParams {
    get {
      CreateParams parms = base.CreateParams;
      parms.ExStyle |= 0x20;  // Turn on WS_EX_TRANSPARENT
      return parms;
    }
  }
}

【讨论】:

  • 好吧,这似乎可行。问题是当它位于进度条之上时。似乎文本有时会消失并重新出现......
  • 不支持堆叠效果,只能跟踪容器的变化。
  • 那么,就像我改变了用户控件的背景颜色一样? (他们之间没有进度条?)
  • 对。或者在容器上绘制的任何其他内容。
  • 我发现如果你省略 Hans 放入的构造函数,它似乎可以工作,直到你将 Enabled 设置为 false,此时透明度丢失了。
【解决方案2】:

WinForms 并不真正支持透明控件,但您可以自己制作透明控件。 See my answer here.

在您的情况下,您可能应该子类化进度条并覆盖 OnPaint 方法以在进度条上绘制文本。

【讨论】:

  • 如何在进度条上绘制文字?
  • 我还没有为进度条做这个,但是你可以为 OnPaint 方法创建一个重载。这里首先调用 base.OnPaint,然后使用事件参数中传递的图形对象在控件顶部绘制文本。
  • 不知道为什么当完整的解决方案在另一个中给出时,为什么一个引用另一个 SO 答案的答案被接受,它说“在 Google 上查找”而不是提供该方法的重要细节在此页面上回答。
【解决方案3】:

最简单的解决方案如下:

  1. 在可视化编辑器或表单的构造函数中将背景颜色设置为透明度:

    this.label1.BackColor = System.Drawing.Color.Transparent;

  2. 设置标签的 Parent 属性以控制您希望在文本后面可见。这可以在表单构造函数或 Load 方法中完成:

    this.label1.Parent = progressBar1;

确实,这不是 DirectX 中的真正透明度。您在显示上看到的结果仅由两层组成。你不能用这种方法总结超过两层(每一层都有自己的透明度,由 alpha 参数定义)。但它适用于您在Winforms编程中可能遇到的许多实际情况。

【讨论】:

    【解决方案4】:

    使用 LinkLabel 而非普通标签

        private void MakeTransparentLabel(System.Windows.Forms.LinkLabel LinkLabel)
        {
            this.MakeTransparentLabel(LinkLabel, Color.White);
        }
        private void MakeTransparentLabel(System.Windows.Forms.LinkLabel LinkLabel, Color ForeColor)
        {
            LinkLabel.ForeColor = ForeColor;
            LinkLabel.LinkColor = ForeColor;
            LinkLabel.VisitedLinkColor = ForeColor;
            LinkLabel.ActiveLinkColor = ForeColor;
            LinkLabel.DisabledLinkColor = ForeColor;
            LinkLabel.LinkArea = new LinkArea(0, 0);
            LinkLabel.LinkBehavior = LinkBehavior.NeverUnderline;
            LinkLabel.Cursor = Cursors.Arrow;
            LinkLabel.BackColor = Color.Transparent;
        }
        private void SetTransparentLabelText(System.Windows.Forms.LinkLabel LinkLabel, string Text)
        {
            if (string.IsNullOrEmpty(Text)) { LinkLabel.Text = " "; return; }
            LinkLabel.Text = Text;
        }
    

    【讨论】:

      【解决方案5】:

      这是一个非常简单的解决方案,效果很好:

      public class MyLabel : Label
      {
          private bool fTransparent = false;
          public bool Transparent
          {
              get { return fTransparent; }
              set { fTransparent = value; }
          }
          public MyLabel() : base()
          {
          }
          protected override CreateParams CreateParams
          {
              get
              {
                  if (fTransparent)
                  {
                      CreateParams cp = base.CreateParams;
                      cp.ExStyle |= 0x00000020; //WS_EX_TRANSPARENT
                      return cp;
                  }
                  else return base.CreateParams;
              }
          }
          protected override void WndProc(ref Message m)
          {
              if (fTransparent)
              {
                  if (m.Msg != 0x14 /*WM_ERASEBKGND*/ && m.Msg != 0x0F /*WM_PAINT*/)
                      base.WndProc(ref m);
                  else 
                  {
                      if (m.Msg == 0x0F) // WM_PAINT
                          base.OnPaint(new PaintEventArgs(Graphics.FromHwnd(Handle), ClientRectangle));
                      DefWndProc(ref m);
                  }
              }
              else base.WndProc(ref m);
          }
      }
      

      当label backcolor是透明的时候,label只会在第一次创建的时候给它的底层控件拍照,之后label backcolor是不变的。并且每次标签重新绘制自己时,它都会重新绘制为固定的颜色或图案。

      重写 CreateParams 会影响控件窗口的创建方式,从而实现真正的透明度。

      重写 WndProc,您可以控制应将哪些消息传递给基类。我们必须过滤 WM_ERASEBKGND 和 WM_PAINT,但我们还必须触发绘制事件。

      【讨论】:

      • 这会在移动的进度条上工作吗?
      • 它应该可以工作,因为这是告诉原生底层控件不要绘制自身的方式。
      【解决方案6】:

      如果你想专注于设计你的 Windows 应用程序,我建议你使用 WPF。

      在 WPF 中使控件透明非常容易。

      <TextBox Width="200" Height="40" Opacity="0.5"/>
      

      【讨论】:

      • 我确信 WPF 可以正确地使用透明标签,但只是想指出,如果将本示例中的代码应用于标签,也会使文本成为半透明的 - 这是不希望的!
      【解决方案7】:

      这是我不久前写的一个透明控件,它显示旋转的文本。大部分代码来自here,尽管我必须对 IIRC 进行一些调整才能使其正常工作。

      using System;
      using System.Drawing;
      using System.Drawing.Drawing2D;
      using System.Drawing.Text;
      using System.Linq;
      using System.Windows.Forms;
      
      namespace MyNamespace
      {
          public partial class RotatedText : UserControl
          {
              private readonly Timer _invalidationTimer;
              private const int WS_EX_TRANSPARENT = 0x00000020;
      
              public RotatedText()
              {
                  this.SetStyle(ControlStyles.SupportsTransparentBackColor, true);
                  InitializeComponent();
      
                  _invalidationTimer = new Timer {Interval = 500, Enabled = true};
                  _invalidationTimer.Tick += TickHandler;
              }
      
              [Browsable(true)]
              [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
              [Category("Appearance")]
              [Description("Text which appears in control")]
              public string Text { get; set; }
      
              #region Transparent background
              protected override CreateParams CreateParams
              {
                  get
                  {
                      CreateParams cp = base.CreateParams;
                      cp.ExStyle |= WS_EX_TRANSPARENT;
                      return cp;
                  }
              }
      
              private void TickHandler(object sender, EventArgs e)
              {
                  InvalidateEx();
              }
      
              private void InvalidateEx()
              {
                  if (Parent != null)
                      Parent.Invalidate(Bounds, false);
                  else
                      Invalidate();
              }
      
              protected override void OnPaintBackground(PaintEventArgs e)
              {
                  //Intentionally do nothing - stops background from drawing
                  //base.OnPaintBackground(e);
              } 
              #endregion
      
              //Rotate text and draw
              protected override void OnPaint(PaintEventArgs e)
              {
                  double angleRadians = Math.Atan2(Height, Width);
                  float angleDegrees = -1*(float) (angleRadians*180/Math.PI);
                  angleDegrees *= 0.9f;
                  e.Graphics.RotateTransform(angleDegrees, MatrixOrder.Append);
                  e.Graphics.TranslateTransform(20, Height - 75, MatrixOrder.Append);
                  e.Graphics.TextRenderingHint = TextRenderingHint.AntiAliasGridFit;
                  Font font = new Font("Ariel", 50);
                  e.Graphics.DrawString(Text, font, Brushes.Gray, 1, 2); //Shadow
                  e.Graphics.DrawString(Text, font, Brushes.Red, 0, 0);
              }
          }
      }
      

      【讨论】:

        【解决方案8】:

        正如我之前回答的评论所说,控制是默认行为,我记得是透明的。

        无论如何,您是否尝试过设置 UserControl 的背景属性,或者您的标签所在的容器(面板、表单等?),您的标签应该反映该颜色 :)


        旧答案: 自从我进行 winforms 编程以来已经有一段时间了,但我记得标签默认情况下是透明的?因此它只有文本获得实际颜色,而免费的颜色模仿它背后的任何东西:)

        【讨论】:

        • 否,Label 默认具有控制背景。但是,您是对的,将其设置为透明确实会模仿托管它的控件的颜色,因此它将背景绘制为纯灰色。
        • 应该启动 WinForms 并检查 :P,真正的 Control 是默认行为,它看起来是透明的,因为它们共享相同的颜色 :)
        【解决方案9】:

        完全可以做到你想要达到的目标。玩控件只需要一点时间。可以创建一个具有透明背景的 Label 控件,并将其放在 Progressbar 控件的顶部。

        检查 my answer to 另一个 SO 问题。

        【讨论】:

          【解决方案10】:

          至于对您的问题的解释,windows 不会像您期望的那样对背景控件进行透明度 - 我猜灰色背景实际上是表单的表面。在表单表面和标签之间绘制的任何控件都将被忽略。

          【讨论】:

            【解决方案11】:

            选择 BackColor,转到 Web 选项卡,然后选择透明。生成以下内容。

                    this.label1.BackColor = System.Drawing.Color.Transparent;
            

            【讨论】:

            • 这就是我所做的,但是在进度条顶部时它不起作用:)
            猜你喜欢
            • 2014-12-29
            • 1970-01-01
            • 2017-04-10
            • 2018-05-21
            • 2012-12-27
            • 1970-01-01
            • 2013-02-20
            • 1970-01-01
            • 2020-03-28
            相关资源
            最近更新 更多