【问题标题】:How Can I Move The Window Like I Want With WinApi如何使用 WinApi 随意移动窗口
【发布时间】:2013-06-06 13:13:49
【问题描述】:

当我尝试用这个拖动我的窗口时,窗口会跳动并闪烁:

protected override void WndProc(ref Message m)
{
    if (m.Msg == WM_MOVE)
    {
        int x = (m.LParam.ToInt32() & 0xffff);
        int y = ((m.LParam.ToInt32() >> 16) & 0xffff);

        if (x < 500)
            Location = new Point(0, y);
        else
            base.WndProc(ref m);
    }
    else
        base.WndProc(ref m);
}
  • 必须停止跳跃
  • WM_MOVEWM_MOVINGWM_WINDOWPOSCHANGING 或其他移动事件必须在拖动窗口时继续触发,因为我希望检查每个新位置。
  • 另一个问题是Location = new Point(0, y); 触发另一个移动事件(这个应该被忽略)

请帮忙!

【问题讨论】:

  • 您是否只是想通过拖动来阻止移动窗口?窗口从哪里开始(你在开始时设置 0,0)?
  • 您忘记了 WM_MOVING 消息。为什么这需要是“winapi”非常不清楚,LocationChanged 事件运行良好。
  • 听起来你应该使用WM_WINDOWPOSCHANGING。您可以更改 WINDOWPOS 结构以修改窗口位置和/或大小。使用 Marshal.PtrToStructure() 将其取出,并使用 Marshal.StructureToPtr() 将其放回;与我使用 WM_GETMINMAXINFO 所做的 here 非常相似。
  • @Idle_Mind 如果我修改不会触发移动/定位事件的 windowpos 结构,对吗?你能回答并帮助如何做到这一点(赚取积分)吗?
  • 最初的移动和“捕捉”会触发一个 Move() 事件,但之后不会生成任何事件......它只会粘在原地。

标签: c# winapi move messages


【解决方案1】:

以下是使用 WM_WINDOWPOSCHANGING 并修改 WINDOWPOS 结构的示例:

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    public struct WINDOWPOS
    {
        public IntPtr hwnd;
        public IntPtr hwndInsertAfter;
        public int x;
        public int y;
        public int cx;
        public int cy;
        public uint flags;
    }

    public const int WM_WINDOWPOSCHANGING = 0x46;

    protected override void WndProc(ref Message m)
    {
        switch (m.Msg)
        {
            case WM_WINDOWPOSCHANGING:
                WINDOWPOS wp = (WINDOWPOS)System.Runtime.InteropServices.Marshal.PtrToStructure(m.LParam, typeof(WINDOWPOS));
                if (true) // ... if somecondition ...
                {
                    // modify the location with x,y:
                    wp.x = 0;
                    wp.y = 0;
                }
                System.Runtime.InteropServices.Marshal.StructureToPtr(wp, m.LParam, true);
                break;
        }

        base.WndProc(ref m);
    }

}

【讨论】:

    【解决方案2】:

    这应该做你想做的:

    protected override void WndProc(ref Message message)
    {
        const Int32 WM_SYSCOMMAND = 0x0112;
        const Int32 SC_MOVE = 0xF010;
    
        switch (message.Msg)
        {
            case WM_SYSCOMMAND:
                Int32 command = message.WParam.ToInt32() & 0xfff0;
                if (command == SC_MOVE)
                {
                    Left = 0;
                    Top = 0;
                    return;
                }
                break;
        }
    
        base.WndProc(ref message);
    }
    

    Hans Passant 建议了LocationChanged 事件,它可以很好地工作。在此示例中,窗口在 0, 0 处冻结,直到鼠标指针移出 500, 500 框:

    private void Form1_LocationChanged(Object sender, EventArgs e)
    {
        if (MousePosition.X > 500 || MousePosition.Y > 500)
            Location = MousePosition;
        else
            Location = new Point(0, 0);
    }
    

    【讨论】:

    • 当您开始移动窗口时,该事件不会经常触发一次。我不希望它一直停留在(0, 0),而是决定何时让它移动或保留在一个位置。
    • 你没有提供任何暗示这种逻辑的东西。如果您希望它成为答案的一部分,您必须说明这一点。
    • 那么这个决策过程是什么?搬家、搬家和什么都不做的标准是什么?将 that 放入 if 块并相应地设置 LeftTop。如Left = MousePostion.X 而不是零。
    • 对不起,也许这是一个误解。请注意问题中的重大修改。
    • 误解是我们不知道你想让它做什么。你抓住窗口,开始移动它,让它跳到0, 0...然后呢?如果您不希望它停留在0, 0,那么什么决定了它何时停留在原地?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-25
    • 2016-10-25
    • 1970-01-01
    • 2011-03-06
    • 1970-01-01
    相关资源
    最近更新 更多