【问题标题】:How to create transparent controls in Windows Forms when controls are layered控件分层时如何在 Windows 窗体中创建透明控件
【发布时间】:2016-11-17 21:04:27
【问题描述】:

我正在尝试实现一个“可填写表单”,其中可编辑的文本字段出现在点阵打印机的预打印表单图像的顶部。 (使用 c# 和 Windows 窗体并以 .Net 2.0 为目标)我的第一个想法是使用图像作为 Windows 窗体背景,但滚动时看起来很糟糕,而且内容也无法正确滚动。

我的下一个尝试是创建一个固定大小的窗口,该窗口带有一个超出窗口边界的面板(用于滚动目的)。我在面板中添加了一个 PictureBox,并在其顶部添加了我的文本框。这工作正常,除了 TextBoxes 不支持透明度,所以我尝试了几种方法使 TextBoxes 透明。一种方法是使用奇怪的背景颜色和透明度键。另一个,在以下链接中描述,是创建一个允许透明度的派生类:

Transparency for windows forms textbox

TextBox with a Transparent Background

这两种方法都不起作用,因为我发现,Windows 窗体中的“透明度”只是意味着窗口的背景被绘制到控件背景上。由于 PictureBox 位于 Window 背景和 TextBox 之间,因此它看起来 TextBox 不透明,而只是具有与 Window 的背景颜色相同的背景颜色。使用透明键方法,整个应用程序变得透明,以便您可以在后台看到 Visual Studio,这不是我想要的。所以现在我正在尝试实现一个派生自 TextBox 并覆盖 OnPaint 或 OnPaintBackground 的类,以将 PictureBox 图像的适当部分绘制到控件背景上,以提供透明度错觉,如下面的链接所述:

How to create a transparent control which works when on top of other controls?

首先,我无法让它工作(我尝试了各种方法,要么得到一个完全黑色的控件,要么只是一个标准的标签背景),其次,我从 DrawToBitmap 方法中得到间歇性 ArgumentExceptions有神秘消息“附加信息:targetBounds”。根据 MSDN 的以下链接,我认为这是因为位图太大 - 无论哪种情况,在这里捕获整个表单图像似乎效率低下,因为我真的只想要它的一小部分。

https://msdn.microsoft.com/en-us/library/system.windows.forms.control.drawtobitmap(v=vs.100).aspx

这是我最近的尝试。有人可以帮我实现 OnPaintBackground 或提出不同的方法吗?提前致谢!

public partial class TransparentTextbox : TextBox
{
    public TransparentTextbox()
    {
        InitializeComponent();
        SetStyle(ControlStyles.OptimizedDoubleBuffer |
                    ControlStyles.AllPaintingInWmPaint |
                    ControlStyles.ResizeRedraw |
                    ControlStyles.UserPaint, true);
    }

    protected override void OnPaintBackground(PaintEventArgs e)
    {
        //base.OnPaintBackground(e); // not sure whether I need this
        if (Parent != null)
        {
            foreach (Control c in Parent.Controls)
            {
                if (c.GetType() == typeof(PictureBox))
                {
                    PictureBox formImg = (PictureBox)c;
                    Bitmap bitmap = new Bitmap(formImg.Width, formImg.Height);
                    formImg.DrawToBitmap(bitmap, formImg.Bounds);
                    e.Graphics.DrawImage(bitmap, -Left, -Top);

                    break;
                }
            }

            Debug.WriteLine(Name + " didn't find the PictureBox.");
        }
    }
}

注意:这已被标记为重复,但我在原始帖子中引用了“重复问题”,并解释了它为什么不起作用。该解决方案仅在文本框直接位于窗口上方时才有效 - 如果另一个控件(例如我的面板和图片框)位于窗口和文本框之间,则 .Net 将窗口背景绘制到文本框背景上,有效地使其背景看起来是灰色的,不透明。

【问题讨论】:

  • 我认为这对于 Windows 窗体标准文本框是不可能的。如果您愿意使用第 3 方套件(我可以推荐),Infragistics 使用背景图像和来源为您的问题提供解决方案。 infragistics.com/community/forums/t/1324.aspx
  • 这是 Windows 窗体中的一个限制,一些 3rd 方组件几乎可以修复。但它会增加大量的重量和对简单 Winforms 项目的引用。切换到 WPF 是不可能的吗?像这样的东西很容易适应。
  • @Reza - 这看起来很有希望 - 示例应用程序基本上正在做我想做的事情。仅包括源代码并将我的透明文本框更改为他的控件之一,就可以得到与我自己的课程相似的结果,但我将深入挖掘 - 如果他的作品,我一定会遗漏一些东西。
  • @KevinBBurns - 我正在尝试制作一个可以在较新的 WPF 应用程序和较旧的 WinForms 应用程序之间共享的类库......我很确定我可以让 WPF 解决方案正常工作,但是一种或另一种我需要使用它的主要地方是在现有的 WinForms 应用程序中。

标签: c# .net winforms


【解决方案1】:

我想我终于弄明白了。我在我的类中添加了一个位图变量,当我实例化文本框时,我将它设置为仅包含位于控件后面的表单图像部分。然后我重载 OnPaintBackground 以显示位图,我重载 OnPaint 以手动绘制文本字符串。这是我的透明文本框类的更新版本:

public partial class TransparentTextbox : TextBox
{
    public Bitmap BgBitmap { get; set; }

    public TransparentTextbox()
    {
        InitializeComponent();
        SetStyle(ControlStyles.OptimizedDoubleBuffer |
                    ControlStyles.AllPaintingInWmPaint |
                    ControlStyles.ResizeRedraw |
                    ControlStyles.UserPaint, true);
    }

    protected override void OnPaint(PaintEventArgs e)
    {
        e.Graphics.DrawString(this.Text, this.Font, Brushes.Black, new PointF(0.0F, 0.0F));
    }

    protected override void OnPaintBackground(PaintEventArgs e)
    {
        e.Graphics.DrawImage(BgBitmap, 0, 0);
    }
}

...这是我如何实例化的相关部分:

Bitmap bgImage = (Bitmap)Bitmap.FromStream(Document.FormImage);

PictureBox pb = new PictureBox();
pb.Image = bgImage;
pb.Size = pb.Image.Size;
pb.Top = 0;
pb.Left = 0;
panel1.Controls.Add(pb);

foreach (FormField field in Document.FormFields)
{
    TransparentTextbox tb = new TransparentTextbox();   
    tb.Width = (int)Math.Ceiling(field.MaxLineWidth * 96.0);
    tb.Height = 22;
    tb.Font = new Font("Courier", 12);
    tb.BorderStyle = BorderStyle.None;
    tb.Text = "Super Neat!";
    tb.TextChanged += tb_TextChanged;
    tb.Left = (int)Math.Ceiling(field.XValue * 96.0);
    tb.Top = (int)Math.Ceiling(field.YValue * 96.0);
    tb.Visible = true;

    Bitmap b = new Bitmap(tb.Width, tb.Height);
    using (Graphics g = Graphics.FromImage(b))
    {
        g.DrawImage(bgImage, new Rectangle(0, 0, b.Width, b.Height), tb.Bounds, GraphicsUnit.Pixel);
        tb.BgBitmap = b;
    }
    panel1.Controls.Add(tb);
}

我仍然需要研究突出显示文本时的文本外观,以及其他类似的事情,但我觉得我在正确的轨道上。向 Reza Aghaei 和 Mangist +1 评论其他可行的解决方案!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-21
    • 2013-11-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-11-07
    相关资源
    最近更新 更多