根据一副 png 图片绘制半透明窗体时,用了 WS_EX_LAYERED
后当前窗体再也不会处理 paint 事件,所以所含的子控件是一辈子也不会画出来的,但是这个控件确实存在,而且可以响应事件 。而此时
windows 画制窗体是使用 UpdateLayeredWindow 这个 api 函数的。
对于按钮,完全可以自己画两个图片然后盖在 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);
}
Windo
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);
}
Windo