用C#写依附于桌面的透明带鼠标穿透窗体的总结。
2010-08-04 16:25
579 查看
最近公司需要做一个桌面程序,功能倒是简单,只不过是对特效要求比较特殊,要求窗体依附于桌面(WIN+D等直接显示桌面的时候不消失)、可以设置透明度、没有数据的地方可以实现鼠标穿透。
搞了半天,也没完全实现,用API可以分别实现 鼠标穿透、窗体透明(这个不用API也可以)。但是当这些特效一旦和依附桌面相结合的时候,通通达不到效果,要么窗体不显示,要么实现不了。而且窗体捕获不到显示桌面时候发送的的消息(估计当WIN+D等显示桌面的时候直接把桌面设置为topmost了,而不给窗体发送消息。)估计是我对桌面的hWnd捕获不对。现在先把代码分别贴出来。以后备用。
PS:我测试的系统是windows7,如果是XP 2000 2003下面代码可以正常实现,在VISA和win7下不行。
最终选择的实现方式。设置窗体和要设置透明控件的BackColor,然后设置窗体的TransparencyKey的颜色和刚才设置BackColor相同
不过唯一不好的地方就是这个依附于桌面,但是要比桌面图标高上一层,所以会遮挡掉桌面图标,我没有找到如何设置窗体为桌面图标的下一层的资料。所以这个问题没法解决,如果您有办法,请留言或者发送邮件到wdw984@126.com。非常感谢。
搞了半天,也没完全实现,用API可以分别实现 鼠标穿透、窗体透明(这个不用API也可以)。但是当这些特效一旦和依附桌面相结合的时候,通通达不到效果,要么窗体不显示,要么实现不了。而且窗体捕获不到显示桌面时候发送的的消息(估计当WIN+D等显示桌面的时候直接把桌面设置为topmost了,而不给窗体发送消息。)估计是我对桌面的hWnd捕获不对。现在先把代码分别贴出来。以后备用。
PS:我测试的系统是windows7,如果是XP 2000 2003下面代码可以正常实现,在VISA和win7下不行。
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; using System.Runtime.InteropServices; namespace Haedu_Job { public partial class mainfrm : Form { public mainfrm() { InitializeComponent(); this.CanPenetrate(); } #region 创建依附于桌面的窗体 [DllImport("user32.dll", EntryPoint = "FindWindow")] public static extern int FindWindow( string lpClassName, string lpWindowName ); [DllImport("user32.dll", EntryPoint = "GetWindow")] //获取窗体句柄,hwnd为源窗口句柄 /*wCmd指定结果窗口与源窗口的关系,它们建立在下述常数基础上: GW_CHILD寻找源窗口的第一个子窗口 GW_HWNDFIRST为一个源子窗口寻找第一个兄弟(同级)窗口,或寻找第一个顶级窗口 GW_HWNDLAST为一个源子窗口寻找最后一个兄弟(同级)窗口,或寻找最后一个顶级窗口 GW_HWNDNEXT为源窗口寻找下一个兄弟窗口 GW_HWNDPREV为源窗口寻找前一个兄弟窗口 GW_OWNER寻找窗口的所有者 */ public static extern int GetWindow( int hwnd, int wCmd ); [DllImport("user32.dll", EntryPoint = "SetParent")] public static extern int SetParent( int hWndChild, int hWndNewParent ); //const int GW_HWNDFIRST = 0; //{同级别 Z 序最上} //const int GW_HWNDLAST = 1; //{同级别 Z 序最下} //const int GW_HWNDNEXT = 2; //{同级别 Z 序之下} //const int GW_HWNDPREV = 3; //{同级别 Z 序之上} const int GW_OWNER = 4; //{属主窗口} const int GW_CHILD = 5;//{子窗口中的最上} //[DllImport("user32.dll", EntryPoint = "GetDesktopWindow")] //public static extern int GetDesktopWindow(); #endregion #region 消息处理 //截取消息,进行处理 //private const int WM_SIZE = 0x0005; //const int SIZE_MAXIMIZED = 2; //const int SIZE_MINIMIZED = 1; //protected override void WndProc(ref Message m) //{ // switch (m.Msg) // { // case WM_SIZE: // if (m.WParam.ToInt32() == SIZE_MAXIMIZED) // { // // 窗体最大化 // WindowState = FormWindowState.Normal; // } // else if (m.WParam.ToInt32() == SIZE_MINIMIZED) // { // // 窗体最小花 // Console.WriteLine("Minimized"); // } // else // { // // 其他 // base.DefWndProc(ref m); // Console.WriteLine(m.WParam.ToInt32().ToString()); // } // break; // default: // base.WndProc(ref m); // //Console.WriteLine(m.LParam.ToString()); // break; // } //} #endregion #region gridveiw边框样色重绘 private void dataGridView1_Paint(object sender, PaintEventArgs e) { e.Graphics.DrawRectangle(Pens.Peru, new Rectangle(0, 0, this.dataGridView1.Width - 1, this.dataGridView1.Height - 1)); } #endregion #region 窗体透明 API方式,备用 签入桌面此API无法工作 [DllImport("user32.dll")] public extern static IntPtr GetDesktopWindow(); [DllImport("user32.dll")] public extern static bool SetLayeredWindowAttributes(IntPtr hwnd, uint crKey, byte bAlpha, uint dwFlags); public static uint LWA_COLORKEY = 0x1; public static uint LWA_ALPHA = 0x2; // 0x00000002; [DllImport("user32.dll")] public extern static uint SetWindowLong(IntPtr hwnd, int nIndex, uint dwNewLong); [DllImport("user32.dll")] public extern static uint GetWindowLong(IntPtr hwnd, int nIndex); public enum WindowStyle : int { GWL_EXSTYLE = -20 } public enum ExWindowStyle : uint { WS_EX_LAYERED = 0x00080000 } private void SetWindowTransparent(byte bAlpha) { try { SetWindowLong(this.Handle, (int)WindowStyle.GWL_EXSTYLE, GetWindowLong(this.Handle, (int)WindowStyle.GWL_EXSTYLE) | (uint)ExWindowStyle.WS_EX_LAYERED); SetLayeredWindowAttributes(this.Handle, 0x003F85CD, bAlpha, LWA_COLORKEY | LWA_ALPHA); } catch { } } protected override CreateParams CreateParams { get { CreateParams cp = base.CreateParams; cp.Parent = GetDesktopWindow(); cp.ExStyle = 0x00000080 | 0x00000008;//WS_EX_TOOLWINDOW | WS_EX_TOPMOST return cp; } } #endregion #region 窗体穿透 private const uint WS_EX_LAYERED = 0x80000; private const int WS_EX_TRANSPARENT = 0x20; private const int GWL_STYLE = (-16); private const int GWL_EXSTYLE = (-20); //private const int LWA_ALPHA = 0x2; public void CanPenetrate() { uint intExTemp = GetWindowLong(this.Handle, GWL_EXSTYLE); uint oldGWLEx = SetWindowLong(this.Handle, GWL_EXSTYLE, WS_EX_TRANSPARENT | WS_EX_LAYERED); SetLayeredWindowAttributes(this.Handle, 0x003F85CD, 100, LWA_ALPHA | LWA_COLORKEY); } #endregion private void mainfrm_FormClosing(object sender, EventArgs e) { } [DllImport("user32.dll")] private static extern bool GetWindowText(int hWnd, StringBuilder title, int maxBufSize); [DllImport("user32.dll", CharSet = CharSet.Auto)] private extern static int GetWindowTextLength(IntPtr hWnd); private void mainfrm_Load(object sender, EventArgs e) { //MessageBox.Show(GetDesktopWindow().ToString()); int hDesktop = FindWindow("Progman", null); //int length = GetWindowTextLength(new IntPtr(hDesktop)); //StringBuilder stringBuilder = new StringBuilder(2 * length + 1); //GetWindowText(hDesktop, stringBuilder, stringBuilder.Capacity); //string strTitle = stringBuilder.ToString(); //MessageBox.Show(strTitle); hDesktop = GetWindow(hDesktop, GW_CHILD); SetParent((int)this.Handle, hDesktop); //this.SetWindowTransparent(50); dataGridView1.Width = this.Width - 10; DataTable dt = new DataTable(); dt.Columns.Add("任务名称"); dt.Columns.Add("当前状态"); dt.Columns.Add("开始日期"); dt.Columns.Add("添加人员"); DataRow dr = dt.NewRow(); dr["任务名称"] = "test"; dr["当前状态"] = "进行"; dr["开始日期"] = "test"; dr["添加人员"] = "test"; dt.Rows.Add(dr); dataGridView1.DataSource = dt; } #region 移动窗体 private Point mouseOffset; //记录鼠标指针的坐标 private bool isMouseDown = false; //记录鼠标按键是否按下 //创建该窗体 MouseDown、MouseMove、MouseUp事件的相应处理程序 private void GB_Title_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e) { int xOffset; int yOffset; if (e.Button == MouseButtons.Left) { xOffset = -e.X; yOffset = -e.Y; mouseOffset = new Point(xOffset, yOffset); isMouseDown = true; } } private void GB_Title_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e) { if (isMouseDown) { Point mousePos = Control.MousePosition; mousePos.Offset(mouseOffset.X, mouseOffset.Y); Location = mousePos; } } private void GB_Title_MouseUp(object sender, System.Windows.Forms.MouseEventArgs e) { // 修改鼠标状态isMouseDown的值 // 确保只有鼠标左键按下并移动时,才移动窗体 if (e.Button == MouseButtons.Left) { isMouseDown = false; } } #endregion private void btn_quit_Click(object sender, EventArgs e) { Application.Exit(); } } }
最终选择的实现方式。设置窗体和要设置透明控件的BackColor,然后设置窗体的TransparencyKey的颜色和刚才设置BackColor相同
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; using System.Runtime.InteropServices; namespace Haedu_Job { public partial class mainfrm : Form { public mainfrm() { InitializeComponent(); } #region 创建依附于桌面的窗体 [DllImport("user32.dll", EntryPoint = "FindWindow")] public static extern int FindWindow( string lpClassName, string lpWindowName ); [DllImport("user32.dll", EntryPoint = "GetWindow")] //获取窗体句柄,hwnd为源窗口句柄 /*wCmd指定结果窗口与源窗口的关系,它们建立在下述常数基础上: GW_CHILD寻找源窗口的第一个子窗口 GW_HWNDFIRST为一个源子窗口寻找第一个兄弟(同级)窗口,或寻找第一个顶级窗口 GW_HWNDLAST为一个源子窗口寻找最后一个兄弟(同级)窗口,或寻找最后一个顶级窗口 GW_HWNDNEXT为源窗口寻找下一个兄弟窗口 GW_HWNDPREV为源窗口寻找前一个兄弟窗口 GW_OWNER寻找窗口的所有者 */ public static extern int GetWindow( int hwnd, int wCmd ); [DllImport("user32.dll", EntryPoint = "SetParent")] public static extern int SetParent( int hWndChild, int hWndNewParent ); //const int GW_HWNDFIRST = 0; //{同级别 Z 序最上} //const int GW_HWNDLAST = 1; //{同级别 Z 序最下} //const int GW_HWNDNEXT = 2; //{同级别 Z 序之下} //const int GW_HWNDPREV = 3; //{同级别 Z 序之上} const int GW_OWNER = 4; //{属主窗口} const int GW_CHILD = 5;//{子窗口中的最上} //[DllImport("user32.dll", EntryPoint = "GetDesktopWindow")] //public static extern int GetDesktopWindow(); #endregion private void mainfrm_FormClosing(object sender, EventArgs e) { } private void mainfrm_Load(object sender, EventArgs e) { DataTable dt = new DataTable(); dt.Columns.Add("任务名称"); dt.Columns.Add("当前状态"); dt.Columns.Add("开始日期"); dt.Columns.Add("添加人员"); DataRow dr = dt.NewRow(); dr["任务名称"] = "test"; dr["当前状态"] = "进行"; dr["开始日期"] = "test"; dr["添加人员"] = "test"; dt.Rows.Add(dr); dataGridView1.DataSource = dt; int hDesktop = FindWindow("Progman", null); hDesktop = GetWindow(hDesktop, GW_CHILD); SetParent((int)this.Handle, hDesktop); this.TopMost = true; } #region 移动窗体 private Point mouseOffset; //记录鼠标指针的坐标 private bool isMouseDown = false; //记录鼠标按键是否按下 //创建该窗体 MouseDown、MouseMove、MouseUp事件的相应处理程序 private void GB_Title_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e) { int xOffset; int yOffset; if (e.Button == MouseButtons.Left) { xOffset = -e.X; yOffset = -e.Y; mouseOffset = new Point(xOffset, yOffset); isMouseDown = true; } } private void GB_Title_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e) { if (isMouseDown) { Point mousePos = Control.MousePosition; mousePos.Offset(mouseOffset.X, mouseOffset.Y); Location = mousePos; } } private void GB_Title_MouseUp(object sender, System.Windows.Forms.MouseEventArgs e) { // 修改鼠标状态isMouseDown的值 // 确保只有鼠标左键按下并移动时,才移动窗体 if (e.Button == MouseButtons.Left) { isMouseDown = false; } } #endregion private void btn_quit_Click(object sender, EventArgs e) { Application.Exit(); } private void button1_Click(object sender, EventArgs e) { int hDesktop = FindWindow("Progman", null); hDesktop = GetWindow(hDesktop, GW_CHILD); SetParent((int)this.Handle, hDesktop); this.TopMost = true; } } }
不过唯一不好的地方就是这个依附于桌面,但是要比桌面图标高上一层,所以会遮挡掉桌面图标,我没有找到如何设置窗体为桌面图标的下一层的资料。所以这个问题没法解决,如果您有办法,请留言或者发送邮件到wdw984@126.com。非常感谢。
相关文章推荐
- C#使用Windows API实现桌面上的遮罩层(鼠标穿透)
- C#窗体设计------鼠标穿透窗体
- C#使用Windows API实现桌面上的遮罩层(鼠标穿透)
- C#制作鼠标可以穿透的窗体
- 怎么实现“鼠标穿透”,即鼠标对窗体失去作用,对着它点右键要出现WINDOWS的桌面右菜单
- C# 鼠标穿透窗体功能
- c# 鼠标穿透窗体 张宇轩
- C#使用Windows API实现桌面上的遮罩层(鼠标穿透)
- C# Winform 窗体美化(五、鼠标穿透)
- C# 鼠标穿透窗体与恢复
- C# 鼠标穿透窗体功能的实现方法
- C#使用Windows API实现桌面上的遮罩层(鼠标穿透)
- 怎么实现“鼠标穿透”,即鼠标对窗体失去作用,对着它点右键要出现WINDOWS的桌面右菜单
- C#制作鼠标可以穿透的窗体
- C#编写Windows桌面应用程序在窗体上滚动字幕
- 总结几种C#窗体间通讯的处理方法
- C#鼠标拖动窗体代码
- C#学习总结之一——c# 实现两个窗体间相互访问
- C#窗体dataGridView控件鼠标双击显示信息
- C#窗体传值方法总结