【问题标题】:Dragging of the form moves the form down拖动表格将表格向下移动
【发布时间】:2016-07-21 14:52:29
【问题描述】:

我有一个 Windows 窗体,我的任务是为窗体添加拖动功能。 “VendorMasterList”是一个标签。我已向该标签添加了鼠标移动、鼠标按下和鼠标向上事件。

如果我尝试拖动,表单会向下移动,然后只能以我想要的方式拖动。我的问题是为什么它会下降?这是我的代码

   private Point startPoint = new Point(0, 0);
   private bool isDragging = false;

   private void lblHeader_MouseDown(object sender, MouseEventArgs e)
    {
       isDragging = true;  // _dragging is your variable flag
       startPoint = new Point(e.X, e.Y);
    }
    private void lblHeader_MouseUp(object sender, MouseEventArgs e)
    {
       isDragging = false;
    }
     private void lblHeader_MouseMove(object sender, MouseEventArgs e)
    {
        if (isDragging)
            {
                Point p = PointToScreen(e.Location);
                this.Location = new Point(p.X - this.startPoint.X, p.Y - this.startPoint.Y);
            }
     }

有没有办法解决这个问题?

新添加的图片

【问题讨论】:

  • 您是在尝试移动页眉还是表单……因为“this.location”会移动表单……
  • 您真的认为像这样使用自定义 chrome 是个好主意吗?保持窗口原样并让用户选择它的外观有什么问题?如果您坚持,请查看非客户区在 Windows 中的工作方式 - 以任何您想要的方式重新绘制非客户区、扩展它甚至只是假装窗口客户区的一部分都非常容易实际上是一个非客户区,对应于表头(并让 Windows 为您进行拖动)。
  • 如果鼠标移到标签上并点击。表格的位置发生了变化。
  • 您可以尝试计算表单的 ClientSize 与表单的实际大小之间的差异 - this.Location = new Point(p.X - this.startPoint.X, p.Y - this.startPoint.Y - (this.Height - this.ClientSize.Height));
  • 您真的只需要处理WM_NCHITTEST 消息,并在鼠标位置在您的“标题”内时返回HTCAPTION。转发其他任何内容的默认值。就是这样。这样你的表单就会神奇地移动,就像任何其他没有被混蛋的表单一样。

标签: c# windows


【解决方案1】:

我没有试过你的代码,但我看到的只是部分正确:-)

您保存初始坐标,该坐标相对于被点击控件的左上角,但您需要保存屏幕坐标

然后鼠标移动,你再次得到一个相对于那个角的点。你遗漏了一些相关的东西:

  1. 您需要根据屏幕坐标计算两点之间的增量,否则将窗口移动到光标下方会给出错误值。
  2. 您需要将此增量添加到表单的当前位置
  3. 您需要保存新的鼠标位置才能正确计算下一个增量

可以通过Cursor.Position获取基于屏幕坐标的当前鼠标位置。

所以你的代码应该是:

private void lblHeader_MouseDown(object sender, MouseEventArgs e)
{
   isDragging = true;  // _dragging is your variable flag
   startPoint = Cursor.Position;
}

private void lblHeader_MouseUp(object sender, MouseEventArgs e)
{
   isDragging = false;
}

private void lblHeader_MouseMove(object sender, MouseEventArgs e)
{
    if (isDragging)
    {
        Point p = Cursor.Position;
        int deltaX = p.X - startPoint.X;
        int deltaY = p.Y - startPoint.Y;
        startPoint = p;

        this.Left += deltaX;
        this.Top += deltaY;
    }
 }

我刚刚在表单上放置了一个面板并实现了上述操作。


@IInspector 说这种方法实际上不是很好是对的,因为它没有考虑到 Windows 可以实际为您处理所有这些。

我会采取的另一种方法(也是更好的方法)是:

  1. 覆盖WndProc方法,如下所示
  2. 完成。不再需要鼠标处理

以下是如何覆盖 WndProc 以执行所需操作的示例:

protected override void WndProc(ref Message m)
{
    const UInt32 WM_NCHITTEST = 0x0084;
    const UInt32 HTCAPTION = 0x2;

    bool handled = false;
    if (m.Msg == WM_NCHITTEST)
    {
        if (<cursor is within the caption area>)
        {
            m.Result = (IntPtr)HTCAPTION;
            handled = true;
        }
    }

    if (!handled)
        base.WndProc(ref m);
}

要限制窗口可以移动的区域,您可以使用以下方法。当然,@IInspectable 会不同意,但你走了这条路 :-)

private void lblHeader_MouseMove(object sender, MouseEventArgs e)
{
    if (isDragging)
    {
        Point p = Cursor.Position;
        int deltaX = p.X - startPoint.X;
        int deltaY = p.Y - startPoint.Y;
        startPoint = p;

        int fX = this.Left + deltaX;
        int fY = this.Top + deltaY;

        if (fX >= 0 && fX + this.Width < Area.Width) this.Left = fX;
        if (fY >= 0 && f> + this.Height < Area.Height) this.Top = fY;
    }
 }

【讨论】:

  • 请不要。它开始如此错误,以至于我甚至在看到更新版本之前就不得不投反对票。 Windows 已经为您完成了所有工作,您的程序实际上不需要做任何事情,除了适当地处理WM_NCHITTEST 消息。只需为相应区域返回HTCAPTION,即可完成。其他一切都可以正常工作(包括移动表单)。
  • @IInspectable 好吧,这不是我的错。 OP 已经有了这个代码,OP 想知道为什么他的代码不起作用,我给出了正确的答案。您可能对此不满意,但这确实不是我的问题或我的答案的问题。我当然知道 WM_NCHITTEST,但这不是 OP 的方式。否则我的回答是完全正确的,因为它可以工作并且完全符合 OP 的要求。你说的都是正确的,但我看不出拒绝投票的理由。随意写下您自己的答案,概述您的方法。
  • @IInspectable 我将您的方法作为替代方法包含在我的答案中。
  • 这是一个非常类似于Eulenspiegel 的响应。您没有提供强大的解决方案,而只是帮助 OP 更有效地射击自己的脚。这甚至不是一个好的建议。快速移动鼠标或按下 [Esc] 键时失败。这种类型的“答案没有用”,因此投反对票。
  • 让我也浏览一下 WM_NCHITTEST
猜你喜欢
  • 1970-01-01
  • 2018-05-01
  • 1970-01-01
  • 2022-01-20
  • 1970-01-01
  • 2018-07-05
  • 1970-01-01
  • 1970-01-01
  • 2023-03-31
相关资源
最近更新 更多