利用SendMessage实现窗口拖动
利用SendMessage实现窗口拖动
周银辉
想想以前用跟踪鼠标位移的方式来实现窗口拖动的方式还真有些傻, 后来, .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个参数传进去.
注意到上面在拖动结束时发送了一个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
}
完整的代码,参考下面, 其支持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);
}
}
}
利用SendMessage实现窗口拖动的更多相关文章
- 利用 canvas 破解 某拖动验证码
利用 canvas 破解 某拖动验证码 http://my.oschina.net/u/237940/blog/337194
- Duilib改进窗口拖动,使整个窗口都能拖动两种方法(转载)
转载:http://www.cnblogs.com/XiHua/articles/3490490.html 转载:http://blog.csdn.net/lostspeed/article/deta ...
- duilib进阶教程 -- 改进窗口拖动 (12)
现在大家应该都知道caption="0,0,0,32",是指示标题栏区了吧,如果想要整个窗口都能拖动呢? 那直接把高度改成和窗口一样不就得了~O(∩_∩)O~ 嗯,这样是可以,比如 ...
- Winform 窗口拖动
把窗口边框去掉后,窗口拖动问题: private Point mouseOffset; //记录鼠标指针的坐标 private bool isMouseDown = false; //记录鼠标按键是否 ...
- 窗体的Alpha通道透明色支持(一旦 Form 被定义为利用 LayeredWindow ,窗口的绘图不再响应沿用多年的 WM_Paint 消息)
参考: http://www.delphibbs.com/delphibbs/dispq.asp?lid=2190768 Windows 2000后,为了支持类似MAC界面的Alpha通道混合效果,提 ...
- 29.QT-自定义窗口拖动、自定义QToolButton/QPushButton开关按钮、界面阴影,声音等总结
自定义窗口及拖动 1.自定义无边框窗口时,需要将窗口标志设为: Qt::FramelessWindowHint |Qt::WindowSystemMenuHint | Qt::WindowMinMax ...
- 【Win32 API】利用SendMessage实现winform与wpf之间的消息传递
原文:[Win32 API]利用SendMessage实现winform与wpf之间的消息传递 引言 有一次心血来潮,突然想研究一下进程间的通信,能够实现消息传递的方法有几种,其中win32ap ...
- C# zedgraph利用另一窗口取得的串口数据绘图
C# zedgraph利用另一窗口获得的串口数据绘图第一次用zedgraph,非常不熟悉,网上很多内容看的云里雾里... 这个程序主界面接收串口数据,而另外一个窗口进行实时曲线绘图,要怎么样实现for ...
- 基于jQuery页面窗口拖动预览效果
今天给大家分享一款基于Query页面窗口拖动预览效果.这是一款基于jQuery+HTML5实现的模拟页面窗口显示拖动窗口预览特效.这款实例适用浏览器:IE8.360.FireFox.Chrome.Sa ...
随机推荐
- 有关Canvas的一点小事—canvas数据和像素点
1. canvas生成base64数据 canvas.toDataURL()生成的数据可以直接给image对象使用作为<img>显示在前端,也可以传给后台生成图片保存.前端生成保存图片的 ...
- Node.js笔记 http fs
const http=require('http'); const fs=require('fs'); var server = http.createServer(function(req, res ...
- POJ 3264 Balanced Lineup 线段树RMQ
http://poj.org/problem?id=3264 题目大意: 给定N个数,还有Q个询问,求每个询问中给定的区间[a,b]中最大值和最小值之差. 思路: 依旧是线段树水题~ #include ...
- 常用到的Linux命令
记录一下日常用到的Linux命令,就当做日志了 1.查看Linux 端口号 netstat -apn | grep 80 2.杀死进程 kill -s 9 pid (tomcat 启动不起来有可 ...
- 自旋锁spinlock解析
1 基础概念 自旋锁与相互排斥锁有点类似,仅仅是自旋锁不会引起调用者睡眠.假设自旋锁已经被别的运行单元保持.调用者就一直循环在那里看是否该自旋锁的保持者已经释放了锁."自旋"一词就 ...
- LA-3708 - Graveyard 简单的模拟一下即可
一开始不知道在想啥,竟然写了个双重for循环的.T T一直WA,又没效率. T T然后在纸上模拟演算,改了,就AC了 以后做题果断要先模拟一下例子...能加深对题目的理解. 当教训吧..太懒导致写了好 ...
- 6、修改应用程序数码相框以支持自动关闭LCD
1. 修改数码相框以自动关闭LCD关闭LCD : 在读取触摸屏的函数中判断:如果15S内无数据,执行: echo auto > /sys/devices/platform/mylcd/power ...
- 【hdu 6194】string string string
[链接]h在这里写链接 [题意] 给你一个字符串s以及一个整数k; 让你找出这个字符串里面,恰好出现了k次的子串的个数. k>=1 [题解] 后缀数组题. 对于输入的字符串.求出它的Height ...
- ASIC DC综合的理解
ASIC DC综合的理解 DC综合流程 输入设计文件+指定的工艺库文件+约束文件 经过DC的综合,输出满足期望的门级网表及综合报告 输入输出数据 输入文件:设计文件(verilog等).工艺库(db) ...
- 【LeetCode-面试算法经典-Java实现】【096-Unique Binary Search Trees(唯一二叉搜索树)】
[096-Unique Binary Search Trees(唯一二叉搜索树)] [LeetCode-面试算法经典-Java实现][全部题目文件夹索引] 原题 Given n, how many s ...