Зробити форму без полів рухомою?


109

Чи є спосіб зробити форму, яка не має меж (для FormBorderStyle встановлено значення "немає"), рухомою, коли миша натискає на форму так само, як якщо б там не було межі?

Відповіді:


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

Це по суті робить точно так само, як захопити заголовок вікна, з точки зору менеджера вікон.


Це для мене зовсім не працює. Код працює просто чудово, все правильно, і моє вікно все ще просто сидить там. Якісь ідеї?
дбр

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

2
Якщо у вас є мітка або значок (або будь-які інші об’єкти переднього плану!), Де ви захоплюєте форму, щоб перетягнути, додайте події мусоулау до цих елементів також. Події форми не можна побачити через об’єкти форми.
Пол Нельсон

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

1
Працювало як шарм для мене !!!! Мені довелося перенести обробку події на панель, яку я розміщував замість форми, але вона спрацювала
Джастін

54

Давайте не ускладнювати речі, ніж вони повинні бути. Я натрапив на стільки фрагментів коду, які дозволяють перетягувати форму навколо (або інший елемент керування). І у багатьох з них є свої недоліки / побічні ефекти. Особливо ті, де вони обманюють Windows думати, що контроль над формою - це фактична форма.

Це, як кажуть, ось мій фрагмент. Я ним користуюся постійно. Я також хотів би зазначити, що ви не повинні використовувати це. Invalidate (); як це люблять робити інші, оскільки це спричиняє мерехтіння форми в деяких випадках. А в деяких випадках так і робиться. Використовуючи це. Оновіть, у мене не було проблем із мерехтінням:

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
dang winforms ... шукав цю відповідь майже дві години .... я новий для c # хоч, ти робив мені чудеса!
PrinceOfRavens

Це саме те, про що я думав, моє єдине питання - це було баггі, як все пекло, поки я не прочитав, як ви це зробили. Спасибі товариш
EasyBB

Цей для мене працював краще, ніж дивовижний крихітний фрагмент над перекриттям WndProc. Зауважте, WndProc зробив свою роботу ... він просто зупинив роботу інших речей. Дякую!
Ммм

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

Він не працює на моно, змінено .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

12

Лише WPF


не маю точного коду для передачі, але в недавньому проекті я думаю, що я використовував подію MouseDown і просто ставлю це:

frmBorderless.DragMove();

Метод Window.DragMove (MSDN)


2
Це, однак, WPF. Гаразд, ОП не точно вказав цього.
Joey

Так, це я щось забув про проект, який я робив. Я просто подивився на Форми, і він недоступний. Вибачте!
Кріс

3
@Chris Це працювало для мене в проекті WPF. Дякуємо, що не видалили відповідь.
Рембунатор

7

Реф. Посилання відео

Це перевірено і легко зрозуміти.

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
Цей код працює, але як його легко зрозуміти? Я не знаю ні про що в цьому сегменті коду, окрім заяви перемикача!
Джамшайд Камран

Це 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
Reza Taibur

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

Ласкаво просимо в стек переповнення - тур , будь ласка, перевірте Як відповісти . Ви повинні надати роз’яснення про те, як цей код вирішує проблему ОП «оригінальний плакат». Це буде кориснішим для всіх, хто перевіряє вашу відповідь.
Mauricio Arias Olave

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 та керування користувачем WPF.

Я закінчив панель стека під назвою 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);
    }

Буде добре, якщо ви підтримаєте свою відповідь якимись поясненнями :)
Mustafamg
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.