根据一副png图片绘制半透明窗体时,用了WS_EX_LAYERED后当前窗体再也不会处理paint事件,所以所含的子控件是一辈子也不会画出来的,但是这个控件确实存在,而且可以响应事件 。而此时windows画制窗体是使用UpdateLayeredWindow这个api函数的。
其实这个问题,3年前就在csdn网友miky的"笨笨钟"发布后就讨论过了,后来出了一个叫桌面天气秀 的东东也采用类似的技术。那时候我有幸拿到了miky的delphi下实现gdi+半透明窗体的一段代码,因为无法画出button等控件和 几位高人讨论过,这里是当时的讨论情况
http://borland.mblogger.cn/jinjazz/posts/21093.aspx
最终并没有很好的解决办法,而是通过大概如下的方法解决的
————————————————————————————————————
对于按钮,完全可以自己画两个图片然后盖在button上面,通过处理button的enter和leave消息来切换者两个图片来表达按钮状态
对于输入框..这个可以用一个让任何人看了都生气地办法,那就是....两个窗体
,的确别人就是这么做的
可以用一个空心窗体只显示该显示的控件,然后盖在你的半透明窗体上面,并处理半透明窗体的move事件,让另外一个窗体同步移动或者做其它事情
效果如下:
以下是一些C#代码,Delphi的就不贴了
主Form的代码
using
System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Runtime.InteropServices;
namespace WindowsApplication7
{
public class Form1 : System.Windows.Forms.Form
{
private System.ComponentModel.IContainer components;
public Form1()
{
//
// Windows 窗体设计器支持所必需的
//
InitializeComponent();
FormBorderStyle = FormBorderStyle.None;
}
/// <summary>
/// 清理所有正在使用的资源。
/// </summary>
protected override void Dispose( bool disposing )
{
if ( disposing )
{
if (components != null )
{
components.Dispose();
}
}
base .Dispose( disposing );
}
Windows Form Designer generated code
/// <summary>
/// 应用程序的主入口点。
/// </summary>
[STAThread]
static void Main()
{
Application.Run( new Form1());
}
Form2 controlFrm = new Form2();
private void button1_Click( object sender, System.EventArgs e)
{
MessageBox.Show(controlFrm,controlFrm.textBox1.Text);
}
protected override CreateParams CreateParams
{
get
{
CreateParams cp = base .CreateParams;
cp.ExStyle |= 0x00080000 ; // This form has to have the WS_EX_LAYERED extended style
return cp;
}
}
private void SetStyle1()
{
Bitmap bm = Image.FromFile( @" Green.png " ) as Bitmap;
Bitmap bm2 = Image.FromFile( @" btn.png " ) as Bitmap;
Graphics g = Graphics.FromImage(bm);
g.DrawImage(bm2, 20 , 20 , new Rectangle( 0 , 0 , 90 , 50 ), GraphicsUnit.Pixel);
g.DrawString( " by jinjazz " , new Font( " Ariel " , 9 , FontStyle.Bold), new SolidBrush(Color.Black), new PointF( 40 , 50 ));
this .SetBitmap(bm, 255 );
}
private void SetStyle2()
{
Bitmap bm = Image.FromFile( @" Green.png " ) as Bitmap;
Bitmap bm2 = Image.FromFile( @" btn.png " ) as Bitmap;
Graphics g = Graphics.FromImage(bm);
g.DrawImage(bm2, 15 , 15 , new Rectangle( 7 , 140 , 100 , 50 ), GraphicsUnit.Pixel);
g.DrawString( " by jinjazz " , new Font( " Ariel " , 9 , FontStyle.Bold), new SolidBrush(Color.Black), new PointF( 40 , 50 ));
this .SetBitmap(bm, 255 );
}
private void Form1_Load( object sender, System.EventArgs e)
{
controlFrm.Show();
SetStyle1();
// this.TopMost = true;
controlFrm.TopMost = true ;
}
private void button1_MouseEnter( object sender, EventArgs e)
{
SetStyle2();
}
private void button1_MouseLeave( object sender, EventArgs e)
{
SetStyle1();
}
public void SetBitmap(Bitmap bitmap, byte opacity)
{
if (bitmap.PixelFormat != PixelFormat.Format32bppArgb)
throw new ApplicationException( " The bitmap must be 32ppp with alpha-channel. " );
// The ideia of this is very simple,
// 1. Create a compatible DC with screen;
// 2. Select the bitmap with 32bpp with alpha-channel in the compatible DC;
// 3. Call the UpdateLayeredWindow.
IntPtr screenDc = Win32.GetDC(IntPtr.Zero);
IntPtr memDc = Win32.CreateCompatibleDC(screenDc);
IntPtr hBitmap = IntPtr.Zero;
IntPtr oldBitmap = IntPtr.Zero;
try
{
hBitmap = bitmap.GetHbitmap(Color.FromArgb( 0 )); // grab a GDI handle from this GDI+ bitmap
oldBitmap = Win32.SelectObject(memDc, hBitmap);
Win32.Size size = new Win32.Size(bitmap.Width, bitmap.Height);
Win32.Point pointSource = new Win32.Point( 0 , 0 );
Win32.Point topPos = new Win32.Point(Left, Top);
Win32.BLENDFUNCTION blend = new Win32.BLENDFUNCTION();
blend.BlendOp = Win32.AC_SRC_OVER;
blend.BlendFlags = 0 ;
blend.SourceConstantAlpha = opacity;
blend.AlphaFormat = Win32.AC_SRC_ALPHA;
Win32.UpdateLayeredWindow(Handle, screenDc, ref topPos, ref size, memDc, ref pointSource, 0 , ref blend, Win32.ULW_ALPHA);
}
finally
{
Win32.ReleaseDC(IntPtr.Zero, screenDc);
if (hBitmap != IntPtr.Zero)
{
Win32.SelectObject(memDc, oldBitmap);
// Windows.DeleteObject(hBitmap); // The documentation says that we have to use the Windows.DeleteObject... but since there is no such method I use the normal DeleteObject from Win32 GDI and it's working fine without any resource leak.
Win32.DeleteObject(hBitmap);
}
Win32.DeleteDC(memDc);
}
}
private System.Windows.Forms.Button button1;
private void Form1_MouseDown( object sender, System.Windows.Forms.MouseEventArgs e)
{
Win32.ReleaseCapture();
Win32.SendMessage( this .Handle.ToInt32(), Win32.WM_SysCommand, Win32.SC_MOVE, 0 );
}
private void Form1_Move( object sender, EventArgs e)
{
controlFrm.Location = this .Location;
}
private void Form1_VisibleChanged( object sender, EventArgs e)
{
controlFrm.Visible = this .Visible;
}
private void Form1_FormClosed( object sender, FormClosedEventArgs e)
{
controlFrm.Close();
}
}
}
using System.Drawing;
using System.Drawing.Imaging;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Runtime.InteropServices;
namespace WindowsApplication7
{
public class Form1 : System.Windows.Forms.Form
{
private System.ComponentModel.IContainer components;
public Form1()
{
//
// Windows 窗体设计器支持所必需的
//
InitializeComponent();
FormBorderStyle = FormBorderStyle.None;
}
/// <summary>
/// 清理所有正在使用的资源。
/// </summary>
protected override void Dispose( bool disposing )
{
if ( disposing )
{
if (components != null )
{
components.Dispose();
}
}
base .Dispose( disposing );
}
Windows Form Designer generated code
/// <summary>
/// 应用程序的主入口点。
/// </summary>
[STAThread]
static void Main()
{
Application.Run( new Form1());
}
Form2 controlFrm = new Form2();
private void button1_Click( object sender, System.EventArgs e)
{
MessageBox.Show(controlFrm,controlFrm.textBox1.Text);
}
protected override CreateParams CreateParams
{
get
{
CreateParams cp = base .CreateParams;
cp.ExStyle |= 0x00080000 ; // This form has to have the WS_EX_LAYERED extended style
return cp;
}
}
private void SetStyle1()
{
Bitmap bm = Image.FromFile( @" Green.png " ) as Bitmap;
Bitmap bm2 = Image.FromFile( @" btn.png " ) as Bitmap;
Graphics g = Graphics.FromImage(bm);
g.DrawImage(bm2, 20 , 20 , new Rectangle( 0 , 0 , 90 , 50 ), GraphicsUnit.Pixel);
g.DrawString( " by jinjazz " , new Font( " Ariel " , 9 , FontStyle.Bold), new SolidBrush(Color.Black), new PointF( 40 , 50 ));
this .SetBitmap(bm, 255 );
}
private void SetStyle2()
{
Bitmap bm = Image.FromFile( @" Green.png " ) as Bitmap;
Bitmap bm2 = Image.FromFile( @" btn.png " ) as Bitmap;
Graphics g = Graphics.FromImage(bm);
g.DrawImage(bm2, 15 , 15 , new Rectangle( 7 , 140 , 100 , 50 ), GraphicsUnit.Pixel);
g.DrawString( " by jinjazz " , new Font( " Ariel " , 9 , FontStyle.Bold), new SolidBrush(Color.Black), new PointF( 40 , 50 ));
this .SetBitmap(bm, 255 );
}
private void Form1_Load( object sender, System.EventArgs e)
{
controlFrm.Show();
SetStyle1();
// this.TopMost = true;
controlFrm.TopMost = true ;
}
private void button1_MouseEnter( object sender, EventArgs e)
{
SetStyle2();
}
private void button1_MouseLeave( object sender, EventArgs e)
{
SetStyle1();
}
public void SetBitmap(Bitmap bitmap, byte opacity)
{
if (bitmap.PixelFormat != PixelFormat.Format32bppArgb)
throw new ApplicationException( " The bitmap must be 32ppp with alpha-channel. " );
// The ideia of this is very simple,
// 1. Create a compatible DC with screen;
// 2. Select the bitmap with 32bpp with alpha-channel in the compatible DC;
// 3. Call the UpdateLayeredWindow.
IntPtr screenDc = Win32.GetDC(IntPtr.Zero);
IntPtr memDc = Win32.CreateCompatibleDC(screenDc);
IntPtr hBitmap = IntPtr.Zero;
IntPtr oldBitmap = IntPtr.Zero;
try
{
hBitmap = bitmap.GetHbitmap(Color.FromArgb( 0 )); // grab a GDI handle from this GDI+ bitmap
oldBitmap = Win32.SelectObject(memDc, hBitmap);
Win32.Size size = new Win32.Size(bitmap.Width, bitmap.Height);
Win32.Point pointSource = new Win32.Point( 0 , 0 );
Win32.Point topPos = new Win32.Point(Left, Top);
Win32.BLENDFUNCTION blend = new Win32.BLENDFUNCTION();
blend.BlendOp = Win32.AC_SRC_OVER;
blend.BlendFlags = 0 ;
blend.SourceConstantAlpha = opacity;
blend.AlphaFormat = Win32.AC_SRC_ALPHA;
Win32.UpdateLayeredWindow(Handle, screenDc, ref topPos, ref size, memDc, ref pointSource, 0 , ref blend, Win32.ULW_ALPHA);
}
finally
{
Win32.ReleaseDC(IntPtr.Zero, screenDc);
if (hBitmap != IntPtr.Zero)
{
Win32.SelectObject(memDc, oldBitmap);
// Windows.DeleteObject(hBitmap); // The documentation says that we have to use the Windows.DeleteObject... but since there is no such method I use the normal DeleteObject from Win32 GDI and it's working fine without any resource leak.
Win32.DeleteObject(hBitmap);
}
Win32.DeleteDC(memDc);
}
}
private System.Windows.Forms.Button button1;
private void Form1_MouseDown( object sender, System.Windows.Forms.MouseEventArgs e)
{
Win32.ReleaseCapture();
Win32.SendMessage( this .Handle.ToInt32(), Win32.WM_SysCommand, Win32.SC_MOVE, 0 );
}
private void Form1_Move( object sender, EventArgs e)
{
controlFrm.Location = this .Location;
}
private void Form1_VisibleChanged( object sender, EventArgs e)
{
controlFrm.Visible = this .Visible;
}
private void Form1_FormClosed( object sender, FormClosedEventArgs e)
{
controlFrm.Close();
}
}
}
显示子控件的Form代码
using
System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
namespace WindowsApplication7
{
public partial class Form2 : Form
{
public Form2()
{
InitializeComponent();
}
private System.ComponentModel.IContainer components = null ;
/// <summary>
/// 清理所有正在使用的资源。
/// </summary>
/// <param name="disposing"> 如果应释放托管资源,为 true;否则为 false。 </param>
protected override void Dispose( bool disposing)
{
if (disposing && (components != null ))
{
components.Dispose();
}
base .Dispose(disposing);
}
Windows 窗体设计器生成的代码
private System.Windows.Forms.Button button1;
internal System.Windows.Forms.TextBox textBox1;
private void button1_Click( object sender, EventArgs e)
{
MessageBox.Show( this .textBox1.Text);
}
}
}
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
namespace WindowsApplication7
{
public partial class Form2 : Form
{
public Form2()
{
InitializeComponent();
}
private System.ComponentModel.IContainer components = null ;
/// <summary>
/// 清理所有正在使用的资源。
/// </summary>
/// <param name="disposing"> 如果应释放托管资源,为 true;否则为 false。 </param>
protected override void Dispose( bool disposing)
{
if (disposing && (components != null ))
{
components.Dispose();
}
base .Dispose(disposing);
}
Windows 窗体设计器生成的代码
private System.Windows.Forms.Button button1;
internal System.Windows.Forms.TextBox textBox1;
private void button1_Click( object sender, EventArgs e)
{
MessageBox.Show( this .textBox1.Text);
}
}
}
调用API的代码
using
System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
namespace WindowsApplication7
{
class Win32
{
public enum Bool
{
False = 0 ,
True
} ;
[StructLayout(LayoutKind.Sequential)]
public struct Point
{
public Int32 x;
public Int32 y;
public Point(Int32 x, Int32 y) { this .x = x; this .y = y; }
}
[StructLayout(LayoutKind.Sequential)]
public struct Size
{
public Int32 cx;
public Int32 cy;
public Size(Int32 cx, Int32 cy) { this .cx = cx; this .cy = cy; }
}
[StructLayout(LayoutKind.Sequential, Pack = 1 )]
struct ARGB
{
public byte Blue;
public byte Green;
public byte Red;
public byte Alpha;
}
[StructLayout(LayoutKind.Sequential, Pack = 1 )]
public struct BLENDFUNCTION
{
public byte BlendOp;
public byte BlendFlags;
public byte SourceConstantAlpha;
public byte AlphaFormat;
}
public const Int32 ULW_COLORKEY = 0x00000001 ;
public const Int32 ULW_ALPHA = 0x00000002 ;
public const Int32 ULW_OPAQUE = 0x00000004 ;
public const byte AC_SRC_OVER = 0x00 ;
public const byte AC_SRC_ALPHA = 0x01 ;
[DllImport( " user32.dll " , ExactSpelling = true , SetLastError = true )]
public static extern Bool UpdateLayeredWindow(IntPtr hwnd, IntPtr hdcDst, ref Point pptDst, ref Size psize, IntPtr hdcSrc, ref Point pprSrc, Int32 crKey, ref BLENDFUNCTION pblend, Int32 dwFlags);
[DllImport( " user32.dll " , ExactSpelling = true , SetLastError = true )]
public static extern IntPtr GetDC(IntPtr hWnd);
[DllImport( " user32.dll " , ExactSpelling = true )]
public static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC);
[DllImport( " gdi32.dll " , ExactSpelling = true , SetLastError = true )]
public static extern IntPtr CreateCompatibleDC(IntPtr hDC);
[DllImport( " gdi32.dll " , ExactSpelling = true , SetLastError = true )]
public static extern Bool DeleteDC(IntPtr hdc);
[DllImport( " gdi32.dll " , ExactSpelling = true )]
public static extern IntPtr SelectObject(IntPtr hDC, IntPtr hObject);
[DllImport( " gdi32.dll " , ExactSpelling = true , SetLastError = true )]
public static extern Bool DeleteObject(IntPtr hObject);
[DllImport( " user32.dll " , EntryPoint = " SendMessage " )]
public static extern int SendMessage( int hWnd, int wMsg, int wParam, int lParam);
[DllImport( " user32.dll " , EntryPoint = " ReleaseCapture " )]
public static extern int ReleaseCapture();
public const int WM_SysCommand = 0x0112 ;
public const int SC_MOVE = 0xF012 ;
public const int SC_MAXIMIZE = 61488 ;
public const int SC_MINIMIZE = 61472 ;
}
}
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
namespace WindowsApplication7
{
class Win32
{
public enum Bool
{
False = 0 ,
True
} ;
[StructLayout(LayoutKind.Sequential)]
public struct Point
{
public Int32 x;
public Int32 y;
public Point(Int32 x, Int32 y) { this .x = x; this .y = y; }
}
[StructLayout(LayoutKind.Sequential)]
public struct Size
{
public Int32 cx;
public Int32 cy;
public Size(Int32 cx, Int32 cy) { this .cx = cx; this .cy = cy; }
}
[StructLayout(LayoutKind.Sequential, Pack = 1 )]
struct ARGB
{
public byte Blue;
public byte Green;
public byte Red;
public byte Alpha;
}
[StructLayout(LayoutKind.Sequential, Pack = 1 )]
public struct BLENDFUNCTION
{
public byte BlendOp;
public byte BlendFlags;
public byte SourceConstantAlpha;
public byte AlphaFormat;
}
public const Int32 ULW_COLORKEY = 0x00000001 ;
public const Int32 ULW_ALPHA = 0x00000002 ;
public const Int32 ULW_OPAQUE = 0x00000004 ;
public const byte AC_SRC_OVER = 0x00 ;
public const byte AC_SRC_ALPHA = 0x01 ;
[DllImport( " user32.dll " , ExactSpelling = true , SetLastError = true )]
public static extern Bool UpdateLayeredWindow(IntPtr hwnd, IntPtr hdcDst, ref Point pptDst, ref Size psize, IntPtr hdcSrc, ref Point pprSrc, Int32 crKey, ref BLENDFUNCTION pblend, Int32 dwFlags);
[DllImport( " user32.dll " , ExactSpelling = true , SetLastError = true )]
public static extern IntPtr GetDC(IntPtr hWnd);
[DllImport( " user32.dll " , ExactSpelling = true )]
public static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC);
[DllImport( " gdi32.dll " , ExactSpelling = true , SetLastError = true )]
public static extern IntPtr CreateCompatibleDC(IntPtr hDC);
[DllImport( " gdi32.dll " , ExactSpelling = true , SetLastError = true )]
public static extern Bool DeleteDC(IntPtr hdc);
[DllImport( " gdi32.dll " , ExactSpelling = true )]
public static extern IntPtr SelectObject(IntPtr hDC, IntPtr hObject);
[DllImport( " gdi32.dll " , ExactSpelling = true , SetLastError = true )]
public static extern Bool DeleteObject(IntPtr hObject);
[DllImport( " user32.dll " , EntryPoint = " SendMessage " )]
public static extern int SendMessage( int hWnd, int wMsg, int wParam, int lParam);
[DllImport( " user32.dll " , EntryPoint = " ReleaseCapture " )]
public static extern int ReleaseCapture();
public const int WM_SysCommand = 0x0112 ;
public const int SC_MOVE = 0xF012 ;
public const int SC_MAXIMIZE = 61488 ;
public const int SC_MINIMIZE = 61472 ;
}
}