winFrom消息处理
我们在做winform的时候,很多时候因为需求问题,要把窗体做的好看点,所以就给窗体加上了很多图片,或者其他资源
从而导致了用户在用鼠标拖动窗体的时候,窗体很卡,CPU占用很高的问题,这些都是因为窗体在拖动的时候频繁的绘制
造成的,那么要避免这些问题,其中的一个解决方法就是减少窗体绘制,或者说只绘制一次,即在用户鼠标放开(MouseUp事件)的时候绘制,代码如下:
2 {
3 [DllImport("user32.dll")]
4 public static extern bool ReleaseCapture();
5 [DllImport("user32.dll")]
6 public static extern bool SendMessage(IntPtr hwnd, int wMsg, int wParam, int lParam);
7
8 private const int WM_SYSCOMMAND = 0x0112;//点击窗口左上角那个图标时的系统信息
9 private const int WM_MOVING = 0x216;//鼠标移动消息
10 private const int SC_MOVE = 0xF010;//移动信息
11 private const int HTCAPTION = 0x0002;//表示鼠标在窗口标题栏时的系统信息
12 private const int WM_NCHITTEST = 0x84;//鼠标在窗体客户区(除了标题栏和边框以外的部分)时发送的消息
13 private const int HTCLIENT = 0x1;//表示鼠标在窗口客户区的系统消息
14 private const int SC_MAXIMIZE = 0xF030;//最大化信息
15 private const int SC_MINIMIZE = 0xF020;//最小化信息
16
17 protected override void WndProc(ref Message m)
18 {
19 switch (m.Msg)
20 {
21 case WM_MOVING: //如果鼠标移
22 base.WndProc(ref m);//调用基类的窗口过程——WndProc方法处理这个消息
23 if (m.Result == (IntPtr)HTCLIENT)//如果返回的是HTCLIENT
24 {
25 m.Result = (IntPtr)HTCAPTION;//把它改为HTCAPTION
26 return;//直接返回退出方法
27 }
28 break;
29 }
30 base.WndProc(ref m);//如果不是鼠标移动或单击消息就调用基类的窗口过程进行处理
31 }
32
33 protected override void OnMouseMove(MouseEventArgs e)
34 {
35 if (e.Button == MouseButtons.Left)
36 {
37 ReleaseCapture();
38 SendMessage(this.Handle, WM_SYSCOMMAND, SC_MOVE + HTCAPTION, 0);
39 }
40 base.OnMouseMove(e);
41 }
42 }
方案1 : 通过重载消息处理实现。重写窗口过程(WndProc),处理一些非客户区消息(WM_NCxxxx),C#中重写窗口过程不用再调用SetWindowLong API了,直接overide一个WndProc就可以了,不用声明api函数。
鼠标的拖动只对窗体本身有效,不能在窗体上的控件区域点击拖动
- protected override void WndProc(ref Message m)
- {
- base.WndProc(ref m);
- if (m.Msg == 0x84)
- {
- switch (m.Result.ToInt32())
- {
- case 1:
- m.Result = new IntPtr(2);
- break;
- }
- }
- }
方案2 : 调用非托管的动态链接库,通过控件的鼠标按下事件(MouseDown)发送一个拖动的消息,可以给控件添加MouseDown事件后,拖动这个控件来移动窗体
- using System.Runtime.InteropServices;
- [DllImport("User32.DLL")]
- public static extern int SendMessage(IntPtr hWnd, uint Msg, int wParam, int lParam);
- [DllImport("User32.DLL")]
- public static extern bool ReleaseCapture();
- public const uint WM_SYSCOMMAND = 0x0112;
- public const int SC_MOVE = 61456;
- public const int HTCAPTION = 2;
- private void Form1_MouseDown(object sender, MouseEventArgs e)
- {
- ReleaseCapture();
- SendMessage(Handle, WM_SYSCOMMAND, SC_MOVE | HTCAPTION, 0);
- }
方案3 : 直接在控件上写事件,朋友的是一个PictureBox 停靠在主窗体,然后主窗体设置的无边框,用的是这中方法
- using System;
- using System.Collections.Generic;
- using System.ComponentModel;
- using System.Data;
- using System.Drawing;
- using System.Text;
- using System.Windows.Forms;
- namespace TestShow
- {
- public partial class Form1 : Form
- {
- public Form1()
- {
- InitializeComponent();
- }
- Point downPoint;
- private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
- {
- downPoint = new Point(e.X, e.Y);
- }
- private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
- {
- if (e.Button == MouseButtons.Left)
- {
- this.Location = new Point(this.Location.X + e.X - downPoint.X,
- this.Location.Y + e.Y - downPoint.Y);
- }
- }
- }
- }
实例007 通过截取系统消息判断鼠标的单击键
《C#开发实战1200例(第II卷)》本书以开发人员在项目开发中经常遇到的问题和必须掌握的技术为中心,介绍了应用C#进行程序开发各个方面的知识和技巧,主要包括鼠标与键盘控制、Windows系统开发、数据库及LINQ开发、水晶报表与打印、注册表操作、软件安全控制等。本节为大家介绍实例007 通过截取系统消息判断鼠标的单击键。
实例007 通过截取系统消息判断鼠标的单击键
光盘位置:光盘\MR\01\007
程序开发中,有效地截取系统消息有时会起到事半功倍的效果,如开发人员可以通过截取系统消息获取鼠标操作或者键盘操作等。本实例通过截取系统消息实现了获取鼠标单击键的功能,实例运行效果如图1.7所示。
498)this.width=498;" height=99> |
图1.7 通过截取系统消息判断鼠标的单击键 |
本实例实现的关键是如何截取系统消息,下面对如何在C#中截取系统消息进行详细讲解。
在C#中截取系统消息时,主要有以下两种方案:
第一种方案,通过在Form中重写Control类的虚方法WndProc来截取Windows消息。
第二种方案,通过实现IMessageFilter接口来创建消息筛选器,从而截取Windows消息。
下面对这两种方案中用到的关键技术进行详细讲解。
(1)WndProc方法
WndProc方法主要用来处理Windows消息,该方法为虚方法,其语法格式如下:
- protected virtual void WndProc(ref Message m)
参数说明
m:Message结构,表示要处理的Windows消息。Message结构的属性及说明如表1.2所示。
表1.2 Message结构的属性及说明
属 性 |
说 明 |
HWnd |
获取或设置消息的窗口句柄 |
LParam |
指定消息的LParam字段 |
Msg |
获取或设置消息的ID号 |
Result |
指定为响应消息处理而向Windows返回的值 |
WParam |
获取或设置消息的WParam字段 |
(2)IMessageFilter接口
IMessageFilter接口用来定义消息筛选器接口,该接口的PreFilterMessage方法用来在调度消息之前将其筛选出来,其语法格式如下:
- bool PreFilterMessage(ref Message m)
参数说明
m:要调度的消息,无法修改此消息。
返回值:如果筛选消息并禁止消息被调度,则为true;如果允许消息继续到达下一个筛选器或控件,则为false。
(1)打开Visual Studio 2008开发环境,新建一个Windows窗体应用程序,并将其命名为SysInfo。
(2)更改默认窗体Form1的Name属性为Frm_Main,在该窗体中添加一个Label控件,用来显示操作程序的提示信息。
(3)程序主要代码如下:
- private void Frm_Main_Load(object sender,
EventArgs e) //窗体加载消息筛选器 - {
- Application.AddMessageFilter(mf);
//添加消息筛选器,以便在向目标传送 Windows 消息时监视这些消息 - }
- private void Frm_Main_FormClosing(object sender,
FormClosingEventArgs e)//从窗体中移除一个消息筛选器 - {
- Application.RemoveMessageFilter(mf);
//从应用程序的消息泵移除一个消息筛选器 - }
- protected override void WndProc(ref Message m)
//方法一,重写WndProc虚方法,与方法二不可同时存在 - {
- switch (m.Msg)
//判断系统消息的ID号 - {
- case 513:
- MessageBox.Show("单击了鼠标左键!", "系统信息");
- m.Result = (IntPtr)0;
//为了响应消息处理而向 Windows 返回的值 - break;
- case 516:
- MessageBox.Show("单击了鼠标右键!", "系统信息");
- m.Result = (IntPtr)0;
//为了响应消息处理而向 Windows 返回的值 - break;
- default:
- base.WndProc(ref m);
- break;
- }
- }
- //方法二,实现IMessageFilter接口,从而获得Windows消息,
与方法一不可同时存在 - public class MessageFilter : IMessageFilter
- {
- public bool PreFilterMessage(ref Message message)
//实现PreFilterMessage方法 - {
- switch (message.Msg)
//判断系统消息的ID号 - {
- case 513:
- MessageBox.Show("单击了鼠标左键!", "系统信息");
- return true;
- case 516:
- MessageBox.Show("单击了鼠标右键!", "系统信息");
- return true;
- default:
- return false;
- }
- }
- }
心法领悟007:如何使用递归法删除文件夹中所有文件?
使用递归法删除文件夹中所有文件时,首先需要生成DirectoryInfo类的一个对象,以指定文件夹,然后生成一个FileSystemInfo类型的数组,用来记录指定文件夹中的所有目录及子目录,最后,循环访问FileSystemInfo类型数组中的文件,并调用FileInfo对象的Delete方法将其一一删除。
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
namespace WindowsApplication2
{
public class Pb_C_MaxFrm
{
Form _MaxFrom;
ESCMsgFrm _ESCFrm;
FormBorderStyle _oriFrmBorderStyle;
FormWindowState _oriFrmWindowState;
bool _bIsMax = false;
public Pb_C_MaxFrm()
{
}
public Pb_C_MaxFrm(Form maxForm)
{
setMaxForm(maxForm);
}
public bool IsMax
{
get { return _bIsMax; }
}
public void setMaxForm(Form maxForm)
{
_MaxFrom = maxForm;
//记录窗体的原始状态
_oriFrmBorderStyle = maxForm.FormBorderStyle;
_oriFrmWindowState = maxForm.WindowState;
_MaxFrom.KeyDown+=new KeyEventHandler(_MaxFrom_KeyDown);
}
bool CheckData()
{
return _MaxFrom == null ? false : true;
}
void _MaxFrom_KeyDown(object sender, KeyEventArgs e)
{
//按下[F11]键执行全屏化
if (e.KeyCode == Keys.F11)
Show();
else if (e.KeyCode == Keys.Escape)//按下[Esc]键返回原始窗体
unShow();
}
public void Show()
{
if (!CheckData())
return;
#region 窗体最大化
if (_MaxFrom.WindowState != FormWindowState.Maximized || _MaxFrom.FormBorderStyle!= FormBorderStyle.None)
{
_MaxFrom.FormBorderStyle = FormBorderStyle.None;
_MaxFrom.WindowState = FormWindowState.Maximized;
#region 启动闪屏
if (_ESCFrm == null)
{
_ESCFrm = new ESCMsgFrm();
_ESCFrm.FormClosed += new FormClosedEventHandler(_ESCFrm_FormClosed);
_ESCFrm.Owner = _MaxFrom;
}
_ESCFrm.Show();
#endregion
}
#endregion
_bIsMax = true;
}
public void unShow()
{
if (!CheckData())
return;
if (_ESCFrm != null)
_ESCFrm.Close();
//返回到初始状态
_MaxFrom.FormBorderStyle = _oriFrmBorderStyle;
_MaxFrom.WindowState = _oriFrmWindowState;
_bIsMax = false;
}
void _ESCFrm_FormClosed(object sender, FormClosedEventArgs e)
{
_ESCFrm = null;
}
}
}
2.[按ESC返回]信息窗口类
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Text;
using System.Windows.Forms;
namespace WindowsApplication2
{
public partial class ESCMsgFrm : Form
{
public ESCMsgFrm()
{
InitializeComponent();
}
#region 窗体效果(暂时未用)
/// <summary>
/// 设置窗体的四角为圆角
/// </summary>
void setCircleCorner()
{
#region 圆角蒙板
System.Drawing.Drawing2D.GraphicsPath GraphicsPath = new System.Drawing.Drawing2D.GraphicsPath();
#region 左上
GraphicsPath.AddRectangle(new Rectangle(0, 0, 5, 5));
GraphicsPath.AddRectangle(new Rectangle(10, 0, 2, 1));
GraphicsPath.AddRectangle(new Rectangle(9, 0, 1, 2));
GraphicsPath.AddRectangle(new Rectangle(8, 0, 1, 2));
GraphicsPath.AddRectangle(new Rectangle(7, 0, 1, 3));
GraphicsPath.AddRectangle(new Rectangle(6, 0, 1, 4));
GraphicsPath.AddRectangle(new Rectangle(5, 0, 1, 5));
GraphicsPath.AddRectangle(new Rectangle(0, 5, 5, 1));
GraphicsPath.AddRectangle(new Rectangle(0, 6, 4, 1));
GraphicsPath.AddRectangle(new Rectangle(0, 7, 3, 1));
GraphicsPath.AddRectangle(new Rectangle(0, 8, 2, 1));
GraphicsPath.AddRectangle(new Rectangle(0, 9, 2, 1));
GraphicsPath.AddRectangle(new Rectangle(0, 10, 1, 1));
GraphicsPath.AddRectangle(new Rectangle(0, 11, 1, 1));
#endregion
#region 右上
GraphicsPath.AddRectangle(new Rectangle(Width - 11, 0, 2, 1));
GraphicsPath.AddRectangle(new Rectangle(Width - 9, 0, 2, 2));
GraphicsPath.AddRectangle(new Rectangle(Width - 7, 0, 1, 3));
GraphicsPath.AddRectangle(new Rectangle(Width - 6, 0, 1, 4));
GraphicsPath.AddRectangle(new Rectangle(Width - 5, 0, 5, 5));
GraphicsPath.AddRectangle(new Rectangle(Width - 4, 5, 4, 1));
GraphicsPath.AddRectangle(new Rectangle(Width - 3, 6, 5, 1));
GraphicsPath.AddRectangle(new Rectangle(Width - 2, 7, 2, 2));
GraphicsPath.AddRectangle(new Rectangle(Width - 1, 9, 1, 2));
#endregion
#region 左下
GraphicsPath.AddRectangle(new Rectangle(0, Height - 5, 5, 1));
GraphicsPath.AddRectangle(new Rectangle(0, Height - 6, 4, 1));
GraphicsPath.AddRectangle(new Rectangle(0, Height - 7, 3, 1));
GraphicsPath.AddRectangle(new Rectangle(0, Height - 9, 2, 2));
GraphicsPath.AddRectangle(new Rectangle(0, Height - 12, 1, 3));
GraphicsPath.AddRectangle(new Rectangle(0, Height - 4, 5, 4));
GraphicsPath.AddRectangle(new Rectangle(5, Height - 4, 1, 4));
GraphicsPath.AddRectangle(new Rectangle(6, Height - 3, 1, 3));
GraphicsPath.AddRectangle(new Rectangle(7, Height - 2, 2, 2));
GraphicsPath.AddRectangle(new Rectangle(9, Height - 1, 3, 1));
#endregion
#region 右下
GraphicsPath.AddRectangle(new Rectangle(Width - 9, Height - 1, 2, 1));
GraphicsPath.AddRectangle(new Rectangle(Width - 7, Height - 2, 1, 2));
GraphicsPath.AddRectangle(new Rectangle(Width - 6, Height - 3, 1, 3));
GraphicsPath.AddRectangle(new Rectangle(Width - 5, Height - 4, 1, 4));
GraphicsPath.AddRectangle(new Rectangle(Width - 4, Height - 4, 4, 4));
GraphicsPath.AddRectangle(new Rectangle(Width - 4, Height - 5, 5, 1));
GraphicsPath.AddRectangle(new Rectangle(Width - 3, Height - 6, 3, 1));
GraphicsPath.AddRectangle(new Rectangle(Width - 2, Height - 8, 2, 2));
GraphicsPath.AddRectangle(new Rectangle(Width - 1, Height - 11, 1, 3));
#endregion
System.Drawing.Region RegionX = new Region();
RegionX.Xor(GraphicsPath);
this.Region = RegionX;
#endregion
}
/// <summary>
/// 圆角透明
/// </summary>
/// <param name="sender"></param>
/// <param name="p_1"></param>
/// <param name="p_2"></param>
private void Type(Control sender, int p_1, double p_2)
{
GraphicsPath oPath = new GraphicsPath();
oPath.AddClosedCurve(new Point[] { new Point(0, sender.Height / p_1),
new Point(sender.Width / p_1, 0),
new Point(sender.Width - sender.Width / p_1, 0),
new Point(sender.Width, sender.Height / p_1),
new Point(sender.Width, sender.Height - sender.Height / p_1),
new Point(sender.Width - sender.Width / p_1, sender.Height),
new Point(sender.Width / p_1, sender.Height),
new Point(0, sender.Height - sender.Height / p_1) },
(float)p_2);
sender.Region = new Region(oPath);
}
#endregion
private void ESCMsgFrm_Load(object sender, EventArgs e)
{
this.ShowInTaskbar = false;//不在任务栏里显示
this.StartPosition = FormStartPosition.CenterScreen;
this.Opacity = 1;
//以下两句话可以保证窗体显示时只显示字体,因为背景色已被设置为透明
//设置窗体背景色为银色
this.BackColor = Color.Silver;
this.TransparencyKey = Color.Silver;//将窗体中银色部分设置为透明
timer1.Interval = 300;
timer1.Start();
}
private void timer1_Tick(object sender, EventArgs e)
{
if (this.Opacity > 0)
{
this.Opacity -= 0.17;
}
else
{
this.Opacity = 0;
this.Close();
}
}
private void ESCMsgFrm_FormClosing(object sender, FormClosingEventArgs e)
{
timer1.Stop();
}
}
}
3.如何调用
public partial class Form2 : Form
{
Pb_C_MaxFrm m;
public Form2()
{
InitializeComponent();
m = new Pb_C_MaxFrm();
m.setMaxForm(this);
}
private void Form2_Load(object sender, EventArgs e)
{
}
}