C# 窗体样式使用WS_EX_LAYERED后,无法绘制windows控件的解决办法
根据一副 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);
}
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;
}
}