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, 
2020new Rectangle(009050
), GraphicsUnit.Pixel);

            g.DrawString(
"by jinjazz"new Font("Ariel"9, FontStyle.Bold), new SolidBrush(Color.Black), new PointF(4050
));

            
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, 
1515new Rectangle(714010050
), GraphicsUnit.Pixel);

            g.DrawString(
"by jinjazz"new Font("Ariel"9, FontStyle.Bold), new SolidBrush(Color.Black), new PointF(4050
));

            
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(00
);
                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, 0ref
 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);
            
        }


       
    }

}

 

 调用 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
;
    }

}

 

 


 

 

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 这条代码设置了一个窗口的扩展样式,其中包含了 WS_EX_TOPMOST、WS_EX_LAYEREDWS_EX_TRANSPARENT 和 WS_EX_TOOLWINDOW 四种样式。其中,WS_EX_TOPMOST 表示这个窗口总在最上面,WS_EX_LAYERED 表示这个窗口使用颜色加权混合方式绘制WS_EX_TRANSPARENT 表示这个窗口是透明的,WS_EX_TOOLWINDOW 表示这个窗口是一个工具窗口。这条代码将扩展样式设置为这些样式的组合,从而使得鼠标可以穿过窗体,直接点击桌面。但是,这条代码并没有提供取消鼠标穿透的方法。如果想要取消鼠标穿透,你可以将窗口的扩展样式设置为不包含 WS_EX_TRANSPARENT 的样式,这样就可以解除鼠标穿透效果了。 ### 回答2: 使用SetWindowLong函数来设置窗口的扩展样式,包括WS_EX_TOPMOST、WS_EX_LAYEREDWS_EX_TRANSPARENT和WS_EX_TOOLWINDOW。其中WS_EX_TOPMOST将窗口设置为最顶层,WS_EX_LAYERED使窗口支持透明效果,WS_EX_TRANSPARENT使窗口透明,并且允许鼠标穿透,WS_EX_TOOLWINDOW将窗口标识为工具窗口。 通过使用以上代码,可以使鼠标可以穿过窗体,直接点击桌面。但是在没有其他的代码进行修改的情况下,无法取消鼠标穿透。如果要取消鼠标穿透,需要进行进一步的操作。 可以使用以下代码取消鼠标穿透功能: SetWindowLong(_hwnd, GWL_EXSTYLE, GetWindowLong(_hwnd, GWL_EXSTYLE) & ~WS_EX_TRANSPARENT); 通过使用GetWindowLong函数获取当前窗口的扩展样式,并且取消WS_EX_TRANSPARENT标志位,最后通过SetWindowLong函数重新设置窗口的扩展样式。 注意:以上操作仅针对当前窗口进行修改,如果要取消其他窗口的鼠标穿透功能,需要在相应的窗口句柄上进行相同的操作。 ### 回答3: 使用SetWindowLong函数设置窗体的扩展样式,包括WS_EX_TOPMOST(窗体置顶)、WS_EX_LAYERED(窗体透明)、WS_EX_TRANSPARENT(鼠标穿透)和WS_EX_TOOLWINDOW(工具窗口)。通过将这些扩展样式使用按位或运算符合并在一起,通过_hwnd参数指定窗体的句柄,可以使鼠标可以穿过窗体直接点击桌面。 然而,根据提供的代码,没有提供取消鼠标穿透的方法。调用SetWindowLong函数并设置新的窗体扩展样式后,将无法通过类似的方式来取消鼠标穿透。如果要取消鼠标穿透,需要重新调用SetWindowLong函数,并在GWL_EXSTYLE参数中使用原始窗体的扩展样式,而不包括WS_EX_TRANSPARENT。这将覆盖之前设置的样式,从而实现取消鼠标穿透的效果。 具体的代码示例如下: ```c++ // 设置窗体的扩展样式,包括鼠标穿透 SetWindowLong(_hwnd, GWL_EXSTYLE, WS_EX_TOPMOST | WS_EX_LAYERED | WS_EX_TRANSPARENT | WS_EX_TOOLWINDOW); // 要取消鼠标穿透,重新设置窗体的扩展样式,将原始样式设置回去(不包括WS_EX_TRANSPARENT) SetWindowLong(_hwnd, GWL_EXSTYLE, originalExStyle); ``` 需注意的是,originalExStyle代表窗体在调用SetWindowLong函数前的扩展样式,需要在调用该函数之前保留该值,以便在取消鼠标穿透时恢复窗体的原始样式。 希望以上解答能对您有所帮助。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值