.NET 里的控件背景色所谓的“透明背景”是通过绘制父控件的背景实现的,并不是真正的透明效果。
因此,当多个具有透明背景色的同级控件重叠时,Z 顺序位于前面的控件会遮挡住 Z 顺序小于它的控件。
现在我想要做一个能够真正实现透明背景的控件,思路如下:
1、模仿微软的做法,把和自己相交的控件的部分绘制为背景色
或者
2、使用传说中的 SetLayeredWindowAttribute 方法(未尝试过)。
对于方法1,在实施的时候出现了一些问题。
我新建了控件,继承于 Panel ,重写了控件的 OnPaitBackground 方法,代码如下:
- C# code
protected override void OnPaintBackground(PaintEventArgs pevent) { paintingBg = true; base.OnPaintBackground(pevent); PaintTransparentBackground(pevent); paintingBg = false; } protected internal void PaintTransparentBackground(PaintEventArgs pevent) { Graphics g = pevent.Graphics; Rectangle myBounds = Bounds; foreach (Control ctrl in Parent.Controls) { if (ctrl != this && ctrl.Visible) { TransparentControl overlappedCtrl = ctrl as TransparentControl; if (null == overlappedCtrl || overlappedCtrl.paintingBg) { if (null == overlappedCtrl) { ctrl.Invalidate(); } continue; } g.ResetTransform(); PaintOverlappedControl(pevent, ctrl); } } g.ResetClip(); } private void PaintOverlappedControl(PaintEventArgs pe, Control overlappedCtrl) { Graphics g = pe.Graphics; Rectangle ctrlRect = overlappedCtrl.Bounds; if (ctrlRect.IntersectsWith(Bounds)) { Rectangle overlappedRect = Rectangle.Intersect(ctrlRect, Bounds); Point clipLeftTop = new Point(overlappedRect.Left - Left, overlappedRect.Top - Top); Rectangle clipRect = new Rectangle(clipLeftTop, overlappedRect.Size); Point orign = new Point(ctrlRect.Left - Left, ctrlRect.Top - Top); Rectangle viewRect = new Rectangle(orign, overlappedRect.Size); //g.SetClip(clipRect); //g.TranslateClip(-orign.X, -orign.Y); //g.RenderingOrigin = new Point(-orign.X, - orign.Y); using (PaintEventArgs args = new PaintEventArgs(g, clipRect)) { this.InvokePaintBackground(overlappedCtrl, args); this.InvokePaint(overlappedCtrl, args); } Region rgn = new Region(ctrlRect); rgn.Exclude(overlappedRect); overlappedCtrl.Invalidate(rgn, true); } }
上面这段代码的没有达到实际的效果,而是这样的怪异效果:
·如果控件和别的控件相交,原先控件的背景没了(如果不和其它控件相交,则正常)
·相交区域绘制的位置总是不正确(我以及多次调整过剪辑区域的位置,均没达到正确的效果)
·控件的文本总是绘制在不正确的位置上。
·如果控件 A 和控件 B 有相交的区域,现在移动控件 B,控件 B 的背景会被刷新,但是控件 A 的背景不被刷新。
哪位高手帮看一下代码出了什么问题,或者给出一个其它的解决方案,谢了~
------解决方案--------------------
LZ可以送10分技术分给我吗?急用`谢谢啦`好心有好报!
------解决方案--------------------
用以下类可以搞定。
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
namespace GISUtilities
{
public class AlphaBlend
{
// Methods
public AlphaBlend()
{
}
public void AlphaBlendNumber(IntPtr Handle, short Num)
{
AlphaBlend.SetLayeredWindowAttributes(Handle, 0, (byte)Num, 2);
}
public void AlphaBlendPercent(IntPtr Handle, short Percent)
{
AlphaBlend.SetLayeredWindowAttributes(Handle, 0, (byte)Math.Round((double)((((double)Percent) / 100) * 255)), 2);
}
public IntPtr FindApplicationWindow([Optional] string WindowClass /* = null */, [Optional] string WindowTitle /* = null */)
{
return AlphaBlend.FindWindow(WindowClass, WindowTitle);
}
[DllImport("user32", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32", CharSet = CharSet.Auto, SetLastError = true)]
private static extern int GetWindowLong(IntPtr Handle, int nIndex);
public void ResetAlphaBlending(IntPtr Handle)
{
int num1 = AlphaBlend.GetWindowLong(Handle, -20);
// The following line has me stumped, in VB, the const WS_EX_LAYERED breaks down to the value 524288
// Yet on the line below is the same number but increased by one, basically it should (boolean here) num1 and not WS_EX_LAYERED
AlphaBlend.SetWindowLong(Handle, -20, num1 & -524289);
}
[DllImport("user32", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
private static extern int SetLayeredWindowAttributes(IntPtr Handle, int crKey, byte bAlpha, int dwFlags);
public void SetupAlphaBlending(IntPtr Handle)
{
int num1 = AlphaBlend.GetWindowLong(Handle, -20);
num1 |= WS_EX_LAYERED;
AlphaBlend.SetWindowLong(Handle, -20, num1);
}
[DllImport("user32", CharSet = CharSet.Auto, SetLastError = true)]
private static extern int SetWindowLong(IntPtr Handle, int nIndex, int dwNewLong);
// Fields
private const short GWL_EXSTYLE = -20;
private const short LWA_ALPHA = 2;
private const short LWA_COLORKEY = 1;
private const int WS_EX_LAYERED = 0x80000;
}
}
------解决方案--------------------
- C# code
using System; using System.Collections.Generic; using System.Text; using System.Runtime.InteropServices; namespace GISUtilities { public class AlphaBlend { // Methods public AlphaBlend() { } public void AlphaBlendNumber(IntPtr Handle, short Num) { AlphaBlend.SetLayeredWindowAttributes(Handle, 0, (byte)Num, 2); } public void AlphaBlendPercent(IntPtr Handle, short Percent) { AlphaBlend.SetLayeredWindowAttributes(Handle, 0, (byte)Math.Round((double)((((double)Percent) / 100) * 255)), 2); } public IntPtr FindApplicationWindow([Optional] string WindowClass /* = null */, [Optional] string WindowTitle /* = null */) { return AlphaBlend.FindWindow(WindowClass, WindowTitle); } [DllImport("user32", CharSet = CharSet.Auto, SetLastError = true)] private static extern IntPtr FindWindow(string lpClassName, string lpWindowName); [DllImport("user32", CharSet = CharSet.Auto, SetLastError = true)] private static extern int GetWindowLong(IntPtr Handle, int nIndex); public void ResetAlphaBlending(IntPtr Handle) { int num1 = AlphaBlend.GetWindowLong(Handle, -20); // The following line has me stumped, in VB, the const WS_EX_LAYERED breaks down to the value 524288 // Yet on the line below is the same number but increased by one, basically it should (boolean here) num1 and not WS_EX_LAYERED AlphaBlend.SetWindowLong(Handle, -20, num1 & -524289); } [DllImport("user32", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)] private static extern int SetLayeredWindowAttributes(IntPtr Handle, int crKey, byte bAlpha, int dwFlags); public void SetupAlphaBlending(IntPtr Handle) { int num1 = AlphaBlend.GetWindowLong(Handle, -20); num1 |= WS_EX_LAYERED; AlphaBlend.SetWindowLong(Handle, -20, num1); } [DllImport("user32", CharSet = CharSet.Auto, SetLastError = true)] private static extern int SetWindowLong(IntPtr Handle, int nIndex, int dwNewLong); // Fields private const short GWL_EXSTYLE = -20; private const short LWA_ALPHA = 2; private const short LWA_COLORKEY = 1; private const int WS_EX_LAYERED = 0x80000; } }