窗体样式使用WS_EX_LAYERED后,无法绘制windows控件的解决办法

根据一副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();
        }


    }

}

显示子控件的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 ;
    }

}

你可能感兴趣的:(windows,object,byte,button,Delphi,Components)