根据一副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
#region
Windows Form Designer generated code
/**/
///
<summary>
///
设计器支持所需的方法 - 不要使用代码编辑器修改
///
此方法的内容。
///
</summary>
private
void
InitializeComponent()
...
{
this
.button1
=
new
System.Windows.Forms.Button();
this
.SuspendLayout();
//
//
button1
//
this
.button1.Cursor
=
System.Windows.Forms.Cursors.Hand;
this
.button1.Location
=
new
System.Drawing.Point(
20
,
20
);
this
.button1.Name
=
"
button1
"
;
this
.button1.Size
=
new
System.Drawing.Size(
113
,
51
);
this
.button1.TabIndex
=
1
;
this
.button1.Text
=
"
button1
"
;
this
.button1.MouseLeave
+=
new
System.EventHandler(
this
.button1_MouseLeave);
this
.button1.Click
+=
new
System.EventHandler(
this
.button1_Click);
this
.button1.MouseEnter
+=
new
System.EventHandler(
this
.button1_MouseEnter);
//
//
Form1
//
this
.AutoScaleBaseSize
=
new
System.Drawing.Size(
6
,
14
);
this
.ClientSize
=
new
System.Drawing.Size(
184
,
123
);
this
.Controls.Add(
this
.button1);
this
.Name
=
"
Form1
"
;
this
.StartPosition
=
System.Windows.Forms.FormStartPosition.CenterScreen;
this
.Text
=
"
Form1
"
;
this
.Load
+=
new
System.EventHandler(
this
.Form1_Load);
this
.VisibleChanged
+=
new
System.EventHandler(
this
.Form1_VisibleChanged);
this
.FormClosed
+=
new
System.Windows.Forms.FormClosedEventHandler(
this
.Form1_FormClosed);
this
.MouseDown
+=
new
System.Windows.Forms.MouseEventHandler(
this
.Form1_MouseDown);
this
.Move
+=
new
System.EventHandler(
this
.Form1_Move);
this
.ResumeLayout(
false
);
}
#endregion
/**/
///
<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 窗体设计器生成的代码
#region
Windows 窗体设计器生成的代码
/**/
///
<summary>
///
设计器支持所需的方法 - 不要
///
使用代码编辑器修改此方法的内容。
///
</summary>
private
void
InitializeComponent()
...
{
this
.button1
=
new
System.Windows.Forms.Button();
this
.textBox1
=
new
System.Windows.Forms.TextBox();
this
.SuspendLayout();
//
//
button1
//
this
.button1.BackColor
=
System.Drawing.SystemColors.Control;
this
.button1.Location
=
new
System.Drawing.Point(
118
,
97
);
this
.button1.Name
=
"
button1
"
;
this
.button1.Size
=
new
System.Drawing.Size(
55
,
23
);
this
.button1.TabIndex
=
0
;
this
.button1.Text
=
"
ok
"
;
this
.button1.UseVisualStyleBackColor
=
false
;
this
.button1.Click
+=
new
System.EventHandler(
this
.button1_Click);
//
//
textBox1
//
this
.textBox1.Location
=
new
System.Drawing.Point(
12
,
99
);
this
.textBox1.Name
=
"
textBox1
"
;
this
.textBox1.Size
=
new
System.Drawing.Size(
100
,
21
);
this
.textBox1.TabIndex
=
1
;
this
.textBox1.Text
=
"
I Love Jinjazz
"
;
//
//
Form2
//
this
.AutoScaleDimensions
=
new
System.Drawing.SizeF(6F, 12F);
this
.AutoScaleMode
=
System.Windows.Forms.AutoScaleMode.Font;
this
.BackColor
=
System.Drawing.Color.LightPink;
this
.ClientSize
=
new
System.Drawing.Size(
184
,
123
);
this
.Controls.Add(
this
.textBox1);
this
.Controls.Add(
this
.button1);
this
.FormBorderStyle
=
System.Windows.Forms.FormBorderStyle.None;
this
.Name
=
"
Form2
"
;
this
.ShowInTaskbar
=
false
;
this
.StartPosition
=
System.Windows.Forms.FormStartPosition.CenterScreen;
this
.Text
=
"
Form2
"
;
this
.TransparencyKey
=
System.Drawing.Color.LightPink;
this
.ResumeLayout(
false
);
this
.PerformLayout();
}
#endregion
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
;
}
}