zoukankan      html  css  js  c++  java
  • 利用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);
                }
            }
            
        }
  • 相关阅读:
    xpath元素定位 绝对路径改成相对路径
    jmeter(十一)csv读取中文乱码问题
    jmeter(十)上传文件遇到的奇葩问题
    jmeter(八)Synchronizing Timer的使用
    jmeter.properties配置文件修改
    jmter命令行-生成压力测试报告
    python(二)字符串、列表、数组、元组、字典
    python配置虚拟环境和包
    验证码测试
    性能测试面试题
  • 原文地址:https://www.cnblogs.com/zhaobl/p/1555932.html
Copyright © 2011-2022 走看看