我有一扇窗(System.Windows.Forms.Form
的子类)没有边框,以便应用自定义样式。当鼠标按钮按下时移动窗口似乎很容易。通过发送WM_NCLBUTTONDOWN
HT_CAPTION
或WM_SYSCOMMAND
0xF102
消息,可以将窗口“拖动”到新位置。但只要鼠标按钮按下,这扇Windows好像是不可能移动的。
一个人可以发送WM_SYSCOMMAND
SC_MOVE
消息,但随后光标在窗口的顶部中心移动,并等待用户按下任何箭头键,以便钩住窗口移动-这至少是尴尬的。我试图伪造一个键按下/释放序列,但当然没有。当我用当前的表单Handle
作为参数调用SendMessage
时,它不起作用,但我猜消息不应该发送到当前的表单。
所需行为为:* 点击 * 一个按钮(即鼠标按钮被释放)移动光标所在的窗体,再次点击释放窗体。这在winapi中是可能的吗?不幸的是我不熟悉它。
附录
**发送按键输入:**我尝试使用SendInput
,因为SendMessage
应该是bad practice。但它仍然没有钩住窗口。我尝试用Marshal.GetLastWin32Error()
读取和打印winapi错误代码,但我得到了一个5,这是拒绝访问。奇怪的是,我收到消息后 * 移动序列结束(即我手动按下一个键或鼠标按钮)。不知道如何解决这个问题。
使用IMessageFilter
(IVSoftware的答案):这是我最终做的,但有两个问题:用Location
属性移动窗口与原生方式相比有延迟(现在没什么大不了的),而且它不会接收主窗体外的鼠标消息。这意味着它不会工作a.对于多屏幕环境b.如果光标移动到应用程序窗体外。我可以为每个监视器创建全屏透明窗体,作为“消息画布”不过,为什么不给予操作系统一个机会呢。
2条答案
按热度按时间lymgl2op1#
据我所知,所需的行为是启用“单击移动”(一种或另一种方式),然后单击多屏幕表面上的任何地方,让无边框表单跟随鼠标移动到新位置。在我的简短测试中,一个似乎有效的解决方案是pinvoke WinApi SetWindowsHookEx,为WH_MOUSE_LL安装一个全局低级钩子,以便拦截
WM_LBUTTONDOWN
。*此答案已修改,以便跟踪问题的更新。
低级全局鼠标钩子
执行移动
在我用来测试这个答案的代码中,将点击发生的按钮居中似乎是很直观的(如果这个偏移不适合你,很容易改变)。
威爱比
2exbekwf2#
这是一个我最终会采用的“可能”的解决方案。这并不是说IVSoftware's answer不起作用,它起作用了,我试过了。这是因为我的解决方案有一些与我正在尝试做的事情相关的优点。要点是:
IMessageFilter
(多亏了SwDevMan81's answer),它提醒我“全局”处理消息的正确方法是 * 不要 * 覆盖WndProc
)优点
缺点
代码(基本部分; github上的完整代码)