利用SendMessage实现窗口拖动
来源:互联网 发布:windows phone 之家 编辑:程序博客网 时间:2024/05/13 01:54
利用SendMessage实现窗口拖动
周银辉
想想以前用跟踪鼠标位移的方式来实现窗口拖动的方式还真有些傻, 后来, .Net3.0以来的Window类内置了DragMove方法, 似乎让我们方便的不少, 但, 最近这个方法也不能满足需求了, 因为我需要DragMove过程中向外发事件来通知我"拖动开始了"和"拖动结束了", 可惜的是Window类没有提供者两个事件 (也曾企图通过其他方式来得到通知, 比如监视MouseUp等, 效果不好).
所以就自己来实现窗口拖动吧
不必同监视鼠标位移手动更新窗口位置, 其实通过向窗口发送SC_MOVE命令来移动窗口就可以了,这个命令会帮我们完成位置计算和更新工作:
注意到上面在拖动结束时发送了一个WM_LBUTTONUP消息, 这是因为当鼠标左键按下(并移动)时我们会调用该函数来开始拖动,你的应用程序师可以检测到开始拖动前的这个MouseDown事件de, 但SC_MOVE会拦截MouseUp来结束拖动.你的应用程序监视不到这个MouseUp事件,所以你可能会发现鼠标左键Down和Up数目不配对, 所以在拖动结束时我们Mock了一个Up事件.
由于SendMessage 方法是不会立即返回的(同步的, SendMessageCallback 与 SendNotifyMessage 是立即放回的), 所以在SendMessage执行完毕时,也就是我们"拖动"操作完毕之时, 所以我们可以在这里调用OnDragAndMoveEnded(hwnd)来引发我们自定义的"拖动结束"事件
SendMessage第三个参数(wParam)可以包含的具体的指令值,可以参考下面的枚举:
完整的代码,参考下面, 其支持WinForm和WPF 窗口:
周银辉
想想以前用跟踪鼠标位移的方式来实现窗口拖动的方式还真有些傻, 后来, .Net3.0以来的Window类内置了DragMove方法, 似乎让我们方便的不少, 但, 最近这个方法也不能满足需求了, 因为我需要DragMove过程中向外发事件来通知我"拖动开始了"和"拖动结束了", 可惜的是Window类没有提供者两个事件 (也曾企图通过其他方式来得到通知, 比如监视MouseUp等, 效果不好).
所以就自己来实现窗口拖动吧
不必同监视鼠标位移手动更新窗口位置, 其实通过向窗口发送SC_MOVE命令来移动窗口就可以了,这个命令会帮我们完成位置计算和更新工作:
public const int SC_MOVE = 0xf012;
public const int WM_SYSCOMMAND = 0x112;
public const int WM_LBUTTONUP = 0x202;
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);
private static void DragAndMoveInner(IntPtr hwnd)
{
OnDragAndMoveStarted(hwnd);
SendMessage(hwnd, WM_SYSCOMMAND, (IntPtr)SC_MOVE, IntPtr.Zero);
SendMessage(hwnd, WM_LBUTTONUP, IntPtr.Zero, IntPtr.Zero);
OnDragAndMoveEnded(hwnd);
}
其中WM_SYSCOMMAND是说明向窗口发送指定的命名, 命令的具体值通过第3个参数传进去.public const int WM_SYSCOMMAND = 0x112;
public const int WM_LBUTTONUP = 0x202;
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);
private static void DragAndMoveInner(IntPtr hwnd)
{
OnDragAndMoveStarted(hwnd);
SendMessage(hwnd, WM_SYSCOMMAND, (IntPtr)SC_MOVE, IntPtr.Zero);
SendMessage(hwnd, WM_LBUTTONUP, IntPtr.Zero, IntPtr.Zero);
OnDragAndMoveEnded(hwnd);
}
注意到上面在拖动结束时发送了一个WM_LBUTTONUP消息, 这是因为当鼠标左键按下(并移动)时我们会调用该函数来开始拖动,你的应用程序师可以检测到开始拖动前的这个MouseDown事件de, 但SC_MOVE会拦截MouseUp来结束拖动.你的应用程序监视不到这个MouseUp事件,所以你可能会发现鼠标左键Down和Up数目不配对, 所以在拖动结束时我们Mock了一个Up事件.
由于SendMessage 方法是不会立即返回的(同步的, SendMessageCallback 与 SendNotifyMessage 是立即放回的), 所以在SendMessage执行完毕时,也就是我们"拖动"操作完毕之时, 所以我们可以在这里调用OnDragAndMoveEnded(hwnd)来引发我们自定义的"拖动结束"事件
SendMessage第三个参数(wParam)可以包含的具体的指令值,可以参考下面的枚举:
public enum WM_SYSCOMMAND_WPARAM
{
SC_FIRST = 0xF000,
// Sizes the window.
SC_SIZE = SC_FIRST,
// Moves the window.
SC_MOVE = SC_FIRST + 0x10,
// Minimizes the window.
SC_MINIMIZE = SC_FIRST + 0x20,
// Maximizes the window.
SC_MAXIMIZE = SC_FIRST + 0x30,
// Moves to the next window.
SC_NEXTWINDOW = SC_FIRST + 0x40,
// Moves to the previous window.
SC_PREVWINDOW = SC_FIRST + 0x50,
// Closes the window.
SC_CLOSE = SC_FIRST + 0x60,
//Scrolls vertically
SC_VSCROLL = SC_FIRST + 0x70,
// Scrolls horizontally.
SC_HSCROLL = SC_FIRST + 0x80,
// Retrieves the window menu as a result of a mouse click.
SC_MOUSEMENU = SC_FIRST + 0x90,
// Retrieves the window menu as a result of a keystroke.
// For more information, see the Remarks section.
SC_KEYMENU = SC_FIRST + 0x100,
SC_ARRANGE = SC_FIRST + 0x110,
// Restores the window to its normal position and size.
SC_RESTORE = SC_FIRST + 0x120,
// Activates the Start menu.
SC_TASKLIST = SC_FIRST + 0x130,
// Executes the screen saver application specified
// in the [boot] section of the System.ini file.
SC_SCREENSAVE = SC_FIRST + 0x140,
// Activates the window associated with the application-specified hot key.
// The lParam parameter identifies the window to activate.
SC_HOTKEY = SC_FIRST + 0x150,
// Selects the default item;
// the user double-clicked the window menu.
SC_DEFAULT = SC_FIRST + 0x160,
// Sets the state of the display.
// This command supports devices that have power-saving features,
// such as a battery-powered personal computer.
// The lParam parameter can have the following values:
// -1 - the display is powering on
// 1 - the display is going to low power
// 2 - the display is being shut off
SC_MONITORPOWER = SC_FIRST + 0x170,
// Changes the cursor to a question mark with a pointer.
// If the user then clicks a control in the dialog box,
// the control receives a WM_HELP message.
SC_CONTEXTHELP = SC_FIRST + 0x180,
SC_SEPARATOR = 0xF00F
}
{
SC_FIRST = 0xF000,
// Sizes the window.
SC_SIZE = SC_FIRST,
// Moves the window.
SC_MOVE = SC_FIRST + 0x10,
// Minimizes the window.
SC_MINIMIZE = SC_FIRST + 0x20,
// Maximizes the window.
SC_MAXIMIZE = SC_FIRST + 0x30,
// Moves to the next window.
SC_NEXTWINDOW = SC_FIRST + 0x40,
// Moves to the previous window.
SC_PREVWINDOW = SC_FIRST + 0x50,
// Closes the window.
SC_CLOSE = SC_FIRST + 0x60,
//Scrolls vertically
SC_VSCROLL = SC_FIRST + 0x70,
// Scrolls horizontally.
SC_HSCROLL = SC_FIRST + 0x80,
// Retrieves the window menu as a result of a mouse click.
SC_MOUSEMENU = SC_FIRST + 0x90,
// Retrieves the window menu as a result of a keystroke.
// For more information, see the Remarks section.
SC_KEYMENU = SC_FIRST + 0x100,
SC_ARRANGE = SC_FIRST + 0x110,
// Restores the window to its normal position and size.
SC_RESTORE = SC_FIRST + 0x120,
// Activates the Start menu.
SC_TASKLIST = SC_FIRST + 0x130,
// Executes the screen saver application specified
// in the [boot] section of the System.ini file.
SC_SCREENSAVE = SC_FIRST + 0x140,
// Activates the window associated with the application-specified hot key.
// The lParam parameter identifies the window to activate.
SC_HOTKEY = SC_FIRST + 0x150,
// Selects the default item;
// the user double-clicked the window menu.
SC_DEFAULT = SC_FIRST + 0x160,
// Sets the state of the display.
// This command supports devices that have power-saving features,
// such as a battery-powered personal computer.
// The lParam parameter can have the following values:
// -1 - the display is powering on
// 1 - the display is going to low power
// 2 - the display is being shut off
SC_MONITORPOWER = SC_FIRST + 0x170,
// Changes the cursor to a question mark with a pointer.
// If the user then clicks a control in the dialog box,
// the control receives a WM_HELP message.
SC_CONTEXTHELP = SC_FIRST + 0x180,
SC_SEPARATOR = 0xF00F
}
完整的代码,参考下面, 其支持WinForm和WPF 窗口:
public static class DragMoveExtention
{
public static event EventHandler DragAndMoveStarted;
public static event EventHandler DragAndMoveEnded;
public const int SC_MOVE = 0xf012;
public const int WM_SYSCOMMAND = 0x112;
public const int WM_LBUTTONUP = 0x202;
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);
private static void DragAndMoveInner(IntPtr hwnd)
{
OnDragAndMoveStarted(hwnd);
SendMessage(hwnd, WM_SYSCOMMAND, (IntPtr)SC_MOVE, IntPtr.Zero);
SendMessage(hwnd, WM_LBUTTONUP, IntPtr.Zero, IntPtr.Zero);
OnDragAndMoveEnded(hwnd);
}
private static void OnDragAndMoveStarted(Object sender)
{
if(DragAndMoveStarted != null)
{
DragAndMoveStarted(sender, EventArgs.Empty);
}
}
private static void OnDragAndMoveEnded(Object sender)
{
if(DragAndMoveEnded != null)
{
DragAndMoveEnded(sender, EventArgs.Empty);
}
}
// use it like this:
// wpfWindow.MouseMove += delegate{ wpfWindow.DragAndMove(); };
public static void DragAndMove(this Window window)
{
if (Mouse.LeftButton == MouseButtonState.Pressed)
{
IntPtr hwnd = new WindowInteropHelper(window).Handle;
DragAndMoveInner(hwnd);
}
}
// use it like this:
// winForm.MouseMove += delegate { winForm.DragAndMove(); };
public static void DragAndMove(this Form form)
{
if (Control.MouseButtons == MouseButtons.Left)
{
DragAndMoveInner(form.Handle);
}
}
}
{
public static event EventHandler DragAndMoveStarted;
public static event EventHandler DragAndMoveEnded;
public const int SC_MOVE = 0xf012;
public const int WM_SYSCOMMAND = 0x112;
public const int WM_LBUTTONUP = 0x202;
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);
private static void DragAndMoveInner(IntPtr hwnd)
{
OnDragAndMoveStarted(hwnd);
SendMessage(hwnd, WM_SYSCOMMAND, (IntPtr)SC_MOVE, IntPtr.Zero);
SendMessage(hwnd, WM_LBUTTONUP, IntPtr.Zero, IntPtr.Zero);
OnDragAndMoveEnded(hwnd);
}
private static void OnDragAndMoveStarted(Object sender)
{
if(DragAndMoveStarted != null)
{
DragAndMoveStarted(sender, EventArgs.Empty);
}
}
private static void OnDragAndMoveEnded(Object sender)
{
if(DragAndMoveEnded != null)
{
DragAndMoveEnded(sender, EventArgs.Empty);
}
}
// use it like this:
// wpfWindow.MouseMove += delegate{ wpfWindow.DragAndMove(); };
public static void DragAndMove(this Window window)
{
if (Mouse.LeftButton == MouseButtonState.Pressed)
{
IntPtr hwnd = new WindowInteropHelper(window).Handle;
DragAndMoveInner(hwnd);
}
}
// use it like this:
// winForm.MouseMove += delegate { winForm.DragAndMove(); };
public static void DragAndMove(this Form form)
{
if (Control.MouseButtons == MouseButtons.Left)
{
DragAndMoveInner(form.Handle);
}
}
}
- 利用SendMessage实现窗口拖动
- 利用WM_NCHITTEST消息实现无标题窗口的拖动
- C# 窗口实现拖动
- Qt实现窗口拖动
- 简单实现窗口拖动
- qml实现窗口拖动
- AJAX实现窗口的拖动
- 实现无标题窗口的拖动
- js实现可拖动窗口
- C#中实现窗口拖动
- js实现窗口拖动代码
- 利用SendMessage实现C#进程间通信
- 利用SendMessage实现C#进程间通信
- 利用SendMessage实现C#进程间通信
- 利用SendMessage实现C#进程间通讯
- 实现自己可以拖动的窗口标题
- 无标题栏窗口拖动的实现
- 可拖动窗口的JS实现
- SICP学习笔记(1.1.6)
- SICP学习笔记(1.1.4~1.1.5)
- SICP学习笔记(1.1.1~1.1.3)
- 一点SICP资料
- [趣味编程]时序图可以这样画
- 利用SendMessage实现窗口拖动
- [WPF]实现密码框的密码绑定
- 创建类似于输入法窗口的非激活窗口
- WPF中的MVVM模式
- 如何在XAML中转义大括号
- [转]VS DEBUG 小技巧
- .net中模拟键盘和鼠标操作
- 如何实现.net程序的进程注入
- [转]Managed, Unmanaged, Native: What Kind of Code Is This?
原创粉丝点击
热门IT博客
热门问题
老师的惩罚
人脸识别
我在镇武司摸鱼那些年
重生之率土为王
我在大康的咸鱼生活
盘龙之生命进化
天生仙种
凡人之先天五行
春回大明朝
姑娘不必设防,我是瞎子
老是感觉有屎意但又拉不出
腹痛腹胀有便意拉不出屎
五十路中出
奔出江湖路
求生之路为什么不出3
用012法怎么看下期出那路
出云号
出云号航母
出云战记
出云岛
出云传奇
出云岛刷dp阵容
出云岛隐藏冈布奥
不思议迷宫出云岛隐藏
不思议迷宫出云岛神木
悠闲岛主 华书云
开元占经 南云岛主
不可思议迷宫出云岛
不可思议迷宫出云岛隐藏
豪欲豪族李云全枫
豪欲家庭李云枫族
都市之虫族大帝 飞翔的云
疾云步级
天山云步舞蹈5级
项级神豪林云
国服什么时候出无限火力
国服无线火力什么时候出
出五服是什么意思
产前
出借女友
出借
出借女友之
出借新婚妻子小菲
出借女友潇儿
出借人
出入口
出入口管理
出入口标志牌
膜结构出入口
湘府路高架桥出入口图
徐州地铁一号线各站出入口图