Сделать форму без полей подвижной?


109

Есть ли способ сделать форму, у которой нет границы (FormBorderStyle имеет значение «none»), подвижной при щелчке мыши по форме, как если бы была граница?

Ответы:


252

В этой статье о 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

8
@dbrree Вы, вероятно, скопировали код, который не будет работать, так как Form1_MouseDownне привязан к фактическому MouseDownсобытию Form1.
Ремон Рами

2
Если у вас есть метка или значок (или любые другие объекты переднего плана!), Где вы захватываете форму для перетаскивания, добавьте событие mousedown к этим элементам. События формы не видны сквозь объекты формы.
Пол Нельсон

1
Вам нужно добавить this.MouseDown += ...к Main()функции для формы
Ричард Пек

1
Сработало для меня как шарм !!!! Мне пришлось перенести обработку событий на панель, которую я вставлял вместо формы, но это сработало
Джастин

54

Давайте не будем усложнять вещи более сложными, чем они должны быть. Я встречал так много фрагментов кода, которые позволяют перетаскивать форму (или другой элемент управления). И у многих из них есть свои недостатки / побочные эффекты. Особенно те, где они обманывают Windows, заставляя думать, что Control в форме является реальной формой.

При этом вот мой фрагмент. Я использую это все время. Также хочу отметить, что вам не следует использовать this.Invalidate (); как и другие, потому что в некоторых случаях это вызывает мерцание формы. И в некоторых случаях так и происходит. Обновить. Используя 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;
    }

1
черт побери, winforms ... искал этот ответ почти два часа ... я новичок в C #, но вы сделали мне чудеса!
PrinceOfRavens

Это именно то, о чем я думал, моя единственная проблема заключалась в том, что он чертовски глючил, пока я не прочитал, как вы это сделали. Спасибо, друг
EasyBB

Это сработало для меня лучше, чем замечательный крошечный фрагмент над переопределением WndProc. Имейте в виду, WndProc действительно работал ... он просто остановил работу других вещей. Спасибо!
Ммм

Вероятно, лучший вариант здесь, поскольку он отлично работает и не полагается на WndProc (может быть легко перенесен на другие платформы с помощью Mono). Можно улучшить, изменив состояние на максимальное / нормальное, если Y <10
Sylverdrag

Он не работает на моно, изменил .net 4.5.2 на mono / net 4.5 и по-прежнему не работает. Пытаюсь найти решение прямо сейчас.
Roger Deep

35

Другой более простой способ сделать то же самое.

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;
}

1
Любой из возможных, что вы можете перемещать форму, удерживая определенный инструмент (например, ярлык).
Thomas W

2
Если дважды щелкнуть, форма будет развернута. Также читайте здесь и там, что это ломает щелчок правой кнопкой мыши.
Себастьяно

19

используйте 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. В качестве простого случая предположим, что вы увеличиваете форму в самой верхней строке пикселей и перетаскиваете ее вверх. Ничего не произойдет, хотя форма будет прыгать, как только вы вернете на нее указатель мыши.
Joey

13

Только WPF


у меня нет точного кода под рукой, но в недавнем проекте я думаю, что использовал событие MouseDown и просто поместил это:

frmBorderless.DragMove();

Метод Window.DragMove (MSDN)


2
Но это WPF. Хорошо, OP точно не указал это.
Джоуи

Да, это то, что я забыл о проекте, над которым работал. Я только что посмотрел на формы, и они недоступны. Сожалею!
Крис,

3
@Chris Это сработало для меня в проекте WPF. Спасибо, что не удалили ответ.
Rembunator

7

Ref. ссылка на видео

Это проверено и легко понять.

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);
}

6
Этот код работает, но как его легко понять? Я ничего не знаю в этом сегменте кода, кроме оператора switch!
Джамшайд Камран

Это WM_NCHITTESTзамаскировано.
Андреас Рейбранд,

4

Нет свойства, которое можно перевернуть, чтобы это произошло волшебным образом. Посмотрите на события формы, и становится довольно просто реализовать это, установив this.Topи this.Left. В частности, вы захотите посмотреть MouseDown, MouseUpи MouseMove.


Я подумал, что мне придется использовать эти события, но я не уверен, что с ними делать. Когда вызывается событие MouseDown, как разрешить перемещение формы?
пользователь

1
Нажав вниз, вы устанавливаете флаг и сохраняете базовые координаты. При движении мыши - если флажок установлен - вы регулируете верх и лево на смещение новых координат мыши. Нажав вверх, вы снимаете флажок.
Мерф,

Тем не менее, вы можете довольно легко сделать это с помощью Windows API, который не зависит от получения событий мыши. Этот метод не работает, если, например, вы захватываете пиксель на самом верхнем крае формы и перетаскиваете его вверх.
Джоуи

4
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
Реза Тайбур

4

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);
      }
}

4

Лучший способ, который я нашел (конечно, модифицированный)

// 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);

4

Это сработало для Меня.

    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);
        }
    }

Добро пожаловать в Stack Overflow - тур , пожалуйста, проверьте Как ответить . Вы должны объяснить, как этот код решает проблему «оригинального плаката» OP. Это будет более полезно для тех, кто проверяет ваш ответ.
Маурисио Ариас Олаве

2

Для .NET Framework 4

Вы можете использовать this.DragMove()для MouseDownсобытия компонента (mainLayout в этом примере), который вы используете для перетаскивания.

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

2

Самый простой способ:

Сначала создайте этикетку с именем label1. Перейдите к событиям label1> события мыши> Label1_Mouse Move и напишите следующее:

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

2

Я пытался сделать подвижную форму окон без полей, которая содержала элемент управления WPF Element Host и элемент управления WPF User.

Я получил панель стека под названием StackPanel в моем пользовательском элементе управления WPF, что казалось логичным, чтобы попробовать щелкнуть, чтобы переместиться. Попытка кода 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);

2

Поскольку некоторые ответы не позволяют перетаскивать дочерние элементы управления, я создал небольшой вспомогательный класс. Следует пройти форму верхнего уровня. При желании можно сделать более универсальным.

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);
        }
    }
}

1

Также, если вам нужно использовать DoubleClick и увеличить / уменьшить форму, вы можете использовать ответ «Первый», создать глобальную переменную типа int, добавлять 1 каждый раз, когда пользователь нажимает на компонент, который вы используете для перетаскивания. Если variable == 2тогда сделайте вашу форму больше / меньше. Также используйте таймер на каждые полсекунды или секунды, чтобы сделать свой variable = 0;


1

Добавление MouseLeftButtonDownобработчика событий в MainWindow сработало для меня.

В функцию события, которая создается автоматически, добавьте следующий код:

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

1

Я расширяю решение от jay_t55 еще одним методом, ToolStrip1_MouseLeaveкоторый обрабатывает событие быстрого перемещения мыши и выхода из области.

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;
}

0

Я попробовал следующее и presto changeo, мое прозрачное окно больше не застывало на месте, но его можно было переместить !! (выбросьте все эти другие сложные решения выше ...)

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

Это ответ для WPF, вопрос о WinForms.
Рэй

0

Форма1 (): 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; }
                }
            };
        }
    }
}

0
   [DllImport("user32.DLL", EntryPoint = "ReleaseCapture")]
    private extern static void ReleaseCapture();

    [DllImport("user32.DLL", EntryPoint = "SendMessage")]
    private extern static void SendMessage(System.IntPtr hWnd, int Msg, int wParam, int lParam);
    private void panelTitleBar_MouseDown(object sender, MouseEventArgs e)
    {
        ReleaseCapture();
        SendMessage(this.Handle, 0x112, 0xf012, 0);
    }

Будет хорошо, если вы подкрепите свой ответ некоторыми пояснениями :)
Мустафамг,
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.