C# 控件分层时如何在Windows窗体中创建透明控件
我试图实现一个“可填充表单”,其中可编辑文本字段显示在点阵打印机预打印表单的图像上方。(使用c#和Windows窗体并以.Net 2.0为目标)我的第一个想法是使用图像作为Windows窗体的背景,但在滚动时它看起来很可怕,而且不能正确滚动内容 我的下一个尝试是创建一个固定大小的窗口,其中的面板溢出了窗口的边界(用于滚动)。我在面板中添加了一个PictureBox,并在其顶部添加了我的文本框。这很好,只是文本框不支持透明,所以我尝试了几种方法使文本框透明。一种方法是使用奇怪的背景色和透明度键。另一个在以下链接中描述的是创建一个允许透明性的派生类: 这两种方法都不起作用,因为我已经发现,Windows窗体中的“透明度”仅仅意味着窗口的背景被绘制到控件背景上。由于PictureBox位于窗口背景和文本框之间,因此它使文本框看起来不是透明的,只是具有与窗口背景色相同的背景色。使用透明键方法,整个应用程序变得透明,以便您可以在后台看到VisualStudio,这不是我想要的。因此,现在我尝试实现一个从TextBox派生的类,该类重写OnPaint或OnPaintBackground,将PictureBox图像的适当部分绘制到控件背景上,以产生如下链接中所述的透明效果: 首先,我无法让它工作(我尝试了各种方法,要么得到一个完全黑色的控件,要么只是一个标准的标签背景),其次,我从DrawToBitmap方法中得到了一些异常,这些异常包含神秘的消息“附加信息:targetBounds”。根据MSDN的以下链接,我相信这是因为位图太大了——不管是哪种情况,在这里捕获整个表单图像似乎效率低下,因为我真的只想要一小块 这是我的最新尝试。有人能帮我实现OnPaintBackground吗,或者建议一种不同的方法?提前谢谢C# 控件分层时如何在Windows窗体中创建透明控件,c#,.net,winforms,C#,.net,Winforms,我试图实现一个“可填充表单”,其中可编辑文本字段显示在点阵打印机预打印表单的图像上方。(使用c#和Windows窗体并以.Net 2.0为目标)我的第一个想法是使用图像作为Windows窗体的背景,但在滚动时它看起来很可怕,而且不能正确滚动内容 我的下一个尝试是创建一个固定大小的窗口,其中的面板溢出了窗口的边界(用于滚动)。我在面板中添加了一个PictureBox,并在其顶部添加了我的文本框。这很好,只是文本框不支持透明,所以我尝试了几种方法使文本框透明。一种方法是使用奇怪的背景色和透明度键。另
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.");
}
}
}
注意:这已经被标记为重复,但我在我的原始帖子中引用了“重复问题”,并解释了为什么它不起作用。该解决方案仅在文本框直接位于窗口上方时有效-如果另一个控件(如my Panel和PictureBox)位于窗口和文本框之间,则.Net会将窗口背景绘制到文本框背景上,从而使其背景看起来呈灰色,不透明。我想我终于弄清了这件事的真相。我在类中添加了一个位图变量,当我实例化文本框时,我将其设置为只包含位于控件后面的表单图像部分。然后我重载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对其他可行解决方案的评论 我认为这在Windows窗体标准文本框中是不可能的。如果您愿意使用第三方工具包(我可以推荐),Infragistics可以使用背景图像和来源为您的问题提供解决方案。看看这篇文章:或者这篇:这是Windows窗体中的一个限制,一些第三方组件几乎可以修复。但它将为一个简单的Winforms项目增加大量的权重和引用。切换到WPF是不可能的吗?像这样的东西很容易适应。@Reza-这看起来很有希望-示例应用程序基本上正在做我想做的事情。只需包含源代码并将我的TransparentTextbox更改为他的一个控件,就可以得到与我自己的类类似的结果,但我会更深入一点——如果他的作品成功的话,我肯定会遗漏一些东西。@KevinBBurns——我正在尝试制作一个类库,可以在较新的WPF应用程序和较旧的WinForms应用程序之间共享。。。我很确定我可以让WPF解决方案正常工作,但无论如何,我需要使用它的主要地方是在现有的WinForms应用程序中。