如何在对控件进行分层时在 Windows 窗体中创建透明控件
本文关键字:控件 Windows 窗体 创建 透明 分层 | 更新日期: 2023-09-27 17:56:56
我正在尝试实现一个"可填写表单",其中可编辑的文本字段出现在点阵打印机的预打印表单的图像顶部。(使用 C# 和 Windows 窗体并面向 .Net 2.0) 我的第一个想法是使用图像作为 Windows 窗体背景,但在滚动时看起来很糟糕,并且也没有正确滚动内容。
我的下一个尝试是创建一个固定大小的窗口,其中包含一个溢出窗口边界的面板(用于滚动目的)。 我在面板中添加了一个图片框,并在它上面添加了我的文本框。 这工作正常,除了文本框不支持透明度,所以我尝试了几种方法来使文本框透明。 一种方法是使用奇怪的背景颜色和透明度键。 以下链接中描述的另一个方法是创建一个允许透明度的派生类:
窗口窗体的透明度文本框
具有透明背景的文本框
这两种方法都不起作用,因为正如我所发现的,Windows 窗体中的"透明度"仅意味着窗口的背景被绘制到控件背景上。 由于图片框位于窗口背景和文本框之间,因此它看起来文本框不是透明的,而只是具有等于窗口背景色的背景色。 使用透明度键方法,整个应用程序变得透明,以便您可以在后台看到Visual Studio,这不是我想要的。 因此,现在我正在尝试实现一个派生自 TextBox 并重写 OnPaint 或 OnPaintBackground 的类,以将 PictureBox 图像的相应部分绘制到控件背景上,以产生透明错觉,如以下链接中所述:
如何创建一个在其他控件之上工作的透明控件?
首先,我无法让它工作(我已经尝试了各种方法,要么得到一个完全黑色的控件,要么只是一个标准的标签背景),其次,我从 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 会将窗口背景绘制到文本框背景上,有效地使其背景显示为灰色,而不是透明。
我想我终于明白了。 我在类中添加了一个 Bitmap 变量,当我实例化文本框时,我将其设置为仅包含位于控件后面的窗体图像部分。 然后我重载 OnPaintBackground 以显示位图,并重载 OnPaint 以手动绘制文本字符串。 下面是我的 TransparentTextbox 类的更新版本:
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);
}
当我突出显示文本时,我仍然需要研究文本的外观,以及其他类似的事情,但我觉得我走在正确的轨道上。 +1 Reza Aghaei和Mangist评论其他可行的解决方案!