【问题标题】:Make a borderless form movable?让无边框形式可移动?
【发布时间】:2010-12-08 06:01:15
【问题描述】:

有没有办法让没有边框(FormBorderStyle 设置为“none”)的表单在鼠标在表单上单击时像有边框一样可移动?

【问题讨论】:

    标签: c# winforms border movable


    【解决方案1】:

    This CodeProject 上的文章详细介绍了一种技术。基本上归结为:

    public const int WM_NCLBUTTONDOWN = 0xA1;
    public const int HT_CAPTION = 0x2;
    
    [System.Runtime.InteropServices.DllImport("user32.dll")]
    public static extern int SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam);
    [System.Runtime.InteropServices.DllImport("user32.dll")]
    public static extern bool ReleaseCapture();
    
    private void Form1_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
    {     
        if (e.Button == MouseButtons.Left)
        {
            ReleaseCapture();
            SendMessage(Handle, WM_NCLBUTTONDOWN, HT_CAPTION, 0);
        }
    }
    

    从窗口管理器的角度来看,这完全与抓取窗口的标题栏完全相同。

    【讨论】:

    • 这对我根本不起作用。代码运行得很好,一切都正确,我的窗口仍然坐在那里。有什么想法吗?
    • @dbrree 你可能复制了代码,因为Form1_MouseDown 没有分配给Form1 的实际MouseDown 事件,所以它不起作用。
    • 如果您有一个标签或图标(或任何其他前景对象!),您正在抓取表单以进行拖动,也可以向这些项目添加 mousedown 事件。表单事件无法看穿表单对象。
    • 您需要在表单的Main()函数中添加this.MouseDown += ...
    • 对我来说就像一个魅力!!!!我不得不将事件处理移到我放置表单的面板上,但它起作用了
    【解决方案2】:

    我们不要让事情变得比他们需要的更困难。我遇到了很多允许您拖动表单(或另一个控件)的代码 sn-ps。他们中的许多人都有自己的缺点/副作用。尤其是那些他们欺骗 Windows 认为窗体上的控件是实际窗体的那些。

    话虽如此,这是我的sn-p。我用它所有的时间。我还要注意你不应该使用 this.Invalidate();就像其他人喜欢做的那样,因为它在某些情况下会导致表单闪烁。在某些情况下,this.Refresh 也是如此。使用this.Update,我没有任何闪烁的问题:

    private bool mouseDown;
    private Point lastLocation;
    
        private void Form1_MouseDown(object sender, MouseEventArgs e)
        {
            mouseDown = true;
            lastLocation = e.Location;
        }
    
        private void Form1_MouseMove(object sender, MouseEventArgs e)
        {
            if(mouseDown)
            {
                this.Location = new Point(
                    (this.Location.X - lastLocation.X) + e.X, (this.Location.Y - lastLocation.Y) + e.Y);
    
                this.Update();
            }
        }
    
        private void Form1_MouseUp(object sender, MouseEventArgs e)
        {
            mouseDown = false;
        }
    

    【讨论】:

    • 这正是我想到的方式,我唯一的问题是在我读到你是如何做到的之前,它一直都是马车。谢谢老哥
    • 这个对我来说比覆盖 WndProc 之上的惊人的小 sn-p 效果更好。请注意,WndProc 确实有效……它只是阻止了其他事情的工作。谢谢!
    • 这可能是最好的选择,因为它运行良好并且不依赖于 WndProc(可以通过 Mono 轻松移植到其他平台)。如果 Y,可以通过将状态更改为最大化/正常来改进
    • 这很好。几个问题。 1)被双击搞砸了。如果e.Clicks == 1,则仅设置mouseDown = true。 2)如果您的表单上有控件(面板),这将不起作用。我所做的是挂钩表单上大多数控件的事件,除了一些没有意义的按钮,如按钮。
    【解决方案3】:

    做同样事情的另一种更简单的方法。

    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            // set this.FormBorderStyle to None here if needed
            // if set to none, make sure you have a way to close the form!
        }
        protected override void WndProc(ref Message m)
        {
            base.WndProc(ref m);
            if (m.Msg == WM_NCHITTEST)
                m.Result = (IntPtr)(HT_CAPTION);
        }
    
        private const int WM_NCHITTEST = 0x84;
        private const int HT_CLIENT = 0x1;
        private const int HT_CAPTION = 0x2;
    }
    

    【讨论】:

    • 任何使您可以通过握住特定工具(例如标签)来移动表单的方法。
    • 如果双击,表单会最大化。还在这里和那里阅读这会破坏右键单击。
    【解决方案4】:

    使用 MouseDown、MouseMove 和 MouseUp。您可以为此设置一个变量标志。我有一个样本,但我认为你需要修改。

    我正在将鼠标操作编码为面板。单击面板后,您的表单将随之移动。

    //Global variables;
    private bool _dragging = false;
    private Point _offset;
    private Point _start_point=new Point(0,0);
    
    
    private void panel1_MouseDown(object sender, MouseEventArgs e)
    {
       _dragging = true;  // _dragging is your variable flag
       _start_point = new Point(e.X, e.Y);
    }
    
    private void panel1_MouseUp(object sender, MouseEventArgs e)
    {
       _dragging = false; 
    }
    
    private void panel1_MouseMove(object sender, MouseEventArgs e)
    {
      if(_dragging)
      {
         Point p = PointToScreen(e.Location);
         Location = new Point(p.X - this._start_point.X,p.Y - this._start_point.Y);     
      }
    }
    

    【讨论】:

    • 是的。正如在其他地方已经说过的,这依赖于仍然生成 MouseMove 事件的表单。作为一个简单的例子,假设您在最顶部的像素行对表单进行分级并向上拖动。什么都不会发生,尽管只要您将鼠标移回表单,表单就会跳来跳去。
    【解决方案5】:

    仅 WPF


    手头没有确切的代码,但在最近的一个项目中,我想我使用了 MouseDown 事件并简单地说:

    frmBorderless.DragMove();
    

    Window.DragMove Method (MSDN)

    【讨论】:

    • 不过,那是 WPF。好的,OP 没有具体说明这一点。
    • 是的,这是我在做的项目中忘记的事情。我刚刚看了表格,它不可用。对不起!
    • @Chris 这在 WPF 项目中对我有用。感谢您不删除答案。
    【解决方案6】:

    Ref. video Link

    这是经过测试且易于理解的。

    protected override void WndProc(ref Message m)
    {
        switch (m.Msg)
        {
            case 0x84:
                base.WndProc(ref m);
                if((int)m.Result == 0x1)
                    m.Result = (IntPtr)0x2;
                return;
        }
    
        base.WndProc(ref m);
    }
    

    【讨论】:

    • 这段代码有效,但它怎么容易理解?除了 switch 语句,我不知道这段代码中的任何内容!
    • 这是WM_NCHITTEST伪装的。
    【解决方案7】:

    它对我有用。

        private Point _mouseLoc;
    
        private void Form1_MouseDown(object sender, MouseEventArgs e)
        {
            _mouseLoc = e.Location;
        }
    
        private void Form1_MouseMove(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                int dx = e.Location.X - _mouseLoc.X;
                int dy = e.Location.Y - _mouseLoc.Y;
                this.Location = new Point(this.Location.X + dx, this.Location.Y + dy);
            }
        }
    

    【讨论】:

    • 是的,如果简单的工作正常,为什么需要变得复杂。 ?
    【解决方案8】:

    没有任何属性可以翻转来让这一切神奇地发生。查看表单的事件,通过设置this.Topthis.Left 来实现它变得相当简单。具体来说,您需要查看MouseDownMouseUpMouseMove

    【讨论】:

    • 我想我必须使用这些事件,但我不确定如何处理它们。调用 MouseDown 事件时,如何让窗体移动?
    • 鼠标按下设置一个标志并存储基本坐标。在鼠标移动时 - 如果设置了标志 - 您可以通过新鼠标坐标的偏移量调整顶部和左侧。鼠标抬起时,您清除标志。
    • 不过,您可以使用 Windows API 相当容易地做到这一点,这并不依赖于仍然获取鼠标事件。例如,如果您抓住表单顶部边缘的一个像素并向上拖动,则此方法确实会失败。
    【解决方案9】:
    public Point mouseLocation;
    private void frmInstallDevice_MouseDown(object sender, MouseEventArgs e)
    {
      mouseLocation = new Point(-e.X, -e.Y);
    }
    
    private void frmInstallDevice_MouseMove(object sender, MouseEventArgs e)
    {
      if (e.Button == MouseButtons.Left)
      {
        Point mousePos = Control.MousePosition;
        mousePos.Offset(mouseLocation.X, mouseLocation.Y);
        Location = mousePos;
      }
    }
    

    这可以解决你的问题....

    【讨论】:

    • 你也可以用“e.Location”代替Control.MousePosition
    【解决方案10】:

    https://social.msdn.microsoft.com/Forums/vstudio/en-US/d803d869-68e6-46ff-9ff1-fabf78d6393c/how-to-make-a-borderless-form-in-c?forum=csharpgeneral

    上面链接中的这段代码在我的例子中起到了作用:)

    protected override void OnMouseDown(MouseEventArgs e)  
    
    {
          base.OnMouseDown(e);
          if (e.Button == MouseButtons.Left)
          {
            this.Capture = false;
            Message msg = Message.Create(this.Handle, 0XA1, new IntPtr(2), IntPtr.Zero);
            this.WndProc(ref msg);
          }
    }
    

    【讨论】:

      【解决方案11】:

      由于某些答案不允许子控件可拖动,因此我创建了一个小助手类。 它应该通过顶级表单。如果需要,可以变得更通用。

      class MouseDragger
      {
          private readonly Form _form;
          private Point _mouseDown;
      
          protected void OnMouseDown(object sender, MouseEventArgs e)
          {
              _mouseDown = e.Location;
          }
      
          protected void OnMouseMove(object sender, MouseEventArgs e)
          {
              if (e.Button == MouseButtons.Left)
              {
                  int dx = e.Location.X - _mouseDown.X;
                  int dy = e.Location.Y - _mouseDown.Y;
                  _form.Location = new Point(_form.Location.X + dx, _form.Location.Y + dy);
              }
          }
          public MouseDragger(Form form)
          {
              _form = form;
      
              MakeDraggable(_form);            
          }
      
          private void MakeDraggable(Control control)
          {
              var type = control.GetType();
              if (typeof(Button).IsAssignableFrom(type))
              {
                  return;
              }
      
              control.MouseDown += OnMouseDown;
              control.MouseMove += OnMouseMove;
      
              foreach (Control child in control.Controls)
              {
                  MakeDraggable(child);
              }
          }
      }
      

      【讨论】:

        【解决方案12】:

        我发现的最佳方式(当然是修改过的)

        // This adds the event handler for the control
        private void AddDrag(Control Control) { Control.MouseDown += new System.Windows.Forms.MouseEventHandler(this.DragForm_MouseDown); }
        public const int WM_NCLBUTTONDOWN = 0xA1;
        public const int HT_CAPTION = 0x2;
        [System.Runtime.InteropServices.DllImportAttribute("user32.dll")]
        public static extern int SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam);
        [System.Runtime.InteropServices.DllImportAttribute("user32.dll")]
        public static extern bool ReleaseCapture();
        
        private void DragForm_MouseDown(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                ReleaseCapture();
                SendMessage(Handle, WM_NCLBUTTONDOWN, HT_CAPTION, 0);
                // Checks if Y = 0, if so maximize the form
                if (this.Location.Y == 0) { this.WindowState = FormWindowState.Maximized; }
            }
        }
        

        要将拖动应用到控件,只需在 InitializeComponent() 之后插入它

        AddDrag(NameOfControl);
        

        【讨论】:

          【解决方案13】:

          对于 .NET Framework 4,

          您可以将this.DragMove() 用于您用于拖动的组件(本例中为mainLayout)的MouseDown 事件。

          private void mainLayout_MouseDown(object sender, MouseButtonEventArgs e)
          {
              this.DragMove();
          }
          

          【讨论】:

          • 这不起作用,.NET 4 没有任何 DragMove() 函数表单。 mainLayout 到底是什么??
          【解决方案14】:

          最简单的方法是:

          首先创建一个名为 label1 的标签。 转到 label1 的事件 > 鼠标事件 > Label1_Mouse 移动并写下这些:

          if (e.Button == MouseButtons.Left){
              Left += e.X;
              Top += e.Y;`
          }
          

          【讨论】:

            【解决方案15】:

            我试图制作一个可移动的无边框窗口窗体,其中包含一个 WPF 元素主机控件和一个 WPF 用户控件。

            我最终在我的 WPF 用户控件中使用了一个名为 StackPanel 的堆栈面板,这似乎是尝试单击移动的合乎逻辑的事情。当我缓慢移动鼠标时,尝试 junmats 的代码有效,但如果我更快地移动鼠标,鼠标会从表单上移开,并且表单会卡在移动中间的某个地方。

            这改进了他对我使用 CaptureMouse 和 ReleaseCaptureMouse 的情况的回答,现在即使我快速移动鼠标,鼠标在移动时也不会离开表单。

            private void StackPanel_MouseDown(object sender, MouseButtonEventArgs e)
            {
                _start_point = e.GetPosition(this);
                StackPanel.CaptureMouse();
            }
            
            private void StackPanel_MouseUp(object sender, MouseButtonEventArgs e)
            {
                StackPanel.ReleaseMouseCapture();
            }
            
            private void StackPanel_MouseMove(object sender, MouseEventArgs e)
            {
                if (StackPanel.IsMouseCaptured)
                {
                    var p = _form.GetMousePositionWindowsForms();
                    _form.Location = new System.Drawing.Point((int)(p.X - this._start_point.X), (int)(p.Y - this._start_point.Y));
                }
            }
            
                //Global variables;
                private Point _start_point = new Point(0, 0);
            

            【讨论】:

              【解决方案16】:

              我正在使用另一种方法 ToolStrip1_MouseLeave 扩展 jay_t55 的解决方案,该方法处理鼠标快速移动并离开该区域的事件。

              private bool mouseDown;
              private Point lastLocation;
              
              private void ToolStrip1_MouseDown(object sender, MouseEventArgs e) {
                  mouseDown = true;
                  lastLocation = e.Location;
              }
              
              private void ToolStrip1_MouseMove(object sender, MouseEventArgs e) {
                  if (mouseDown) {
                      this.Location = new Point(
                          (this.Location.X - lastLocation.X) + e.X, (this.Location.Y - lastLocation.Y) + e.Y);
              
                      this.Update();
                  }
              }
              
              private void ToolStrip1_MouseUp(object sender, MouseEventArgs e) {
                  mouseDown = false;
              }
              
              private void ToolStrip1_MouseLeave(object sender, EventArgs e) {
                  mouseDown = false;
              }
              

              【讨论】:

                【解决方案17】:

                此外,如果您需要 DoubleClick 并使您的 Form 更大/更小,您可以使用第一个答案,创建一个全局 int 变量,每次用户单击您用于拖动的组件时添加 1。如果variable == 2 则使您的表单更大/更小。还可以每隔半秒或一秒使用一个计时器来制作您的variable = 0

                【讨论】:

                  【解决方案18】:

                  MouseLeftButtonDown 事件处理程序添加到 MainWindow 对我有用。

                  在自动生成的事件函数中,添加如下代码:

                  base.OnMouseLeftButtonDown(e);
                  this.DragMove();
                  

                  【讨论】:

                    【解决方案19】:

                    Form1():new Moveable(control1, control2, control3);

                    类:

                    using System;
                    using System.Windows.Forms;
                    
                    class Moveable
                    {
                        public const int WM_NCLBUTTONDOWN = 0xA1;
                        public const int HT_CAPTION = 0x2;
                        [System.Runtime.InteropServices.DllImportAttribute("user32.dll")]
                        public static extern int SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam);
                        [System.Runtime.InteropServices.DllImportAttribute("user32.dll")]
                        public static extern bool ReleaseCapture();
                        public Moveable(params Control[] controls)
                        {
                            foreach (var ctrl in controls)
                            {
                                ctrl.MouseDown += (s, e) =>
                                {
                                    if (e.Button == MouseButtons.Left)
                                    {
                                        ReleaseCapture();
                                        SendMessage(ctrl.FindForm().Handle, WM_NCLBUTTONDOWN, HT_CAPTION, 0);
                                        // Checks if Y = 0, if so maximize the form
                                        if (ctrl.FindForm().Location.Y == 0) { ctrl.FindForm().WindowState = FormWindowState.Maximized; }
                                    }
                                };
                            }
                        }
                    }
                    

                    【讨论】:

                      【解决方案20】:

                      我尝试了以下和presto changeo,我的透明窗口不再被冻结但可以移动! (扔掉上面所有其他复杂的解决方案......)

                         private void Window_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
                          {
                              base.OnMouseLeftButtonDown(e);
                              // Begin dragging the window
                              this.DragMove();
                          }
                      

                      【讨论】:

                      • 这个答案是针对WPF的,问题是关于WinForms的。
                      猜你喜欢
                      • 1970-01-01
                      • 1970-01-01
                      • 2018-08-29
                      • 2011-04-22
                      • 1970-01-01
                      • 2011-07-02
                      • 2016-08-09
                      • 1970-01-01
                      相关资源
                      最近更新 更多