테두리없는 형태를 움직일 수 있도록 만드시겠습니까?


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.
Remon Ramy

2
드래그 할 폼을 잡는 위치에 레이블이나 아이콘 (또는 다른 전경 개체!)이있는 경우 이러한 항목에도 mousedown 이벤트를 추가합니다. 양식 이벤트는 양식 개체를 통해 볼 수 없습니다.
Paul Nelson

1
당신은 추가 할 필요가 this.MouseDown += ...받는 Main()폼의 기능
리처드 펙에게

1
나를 위해 매력처럼 일했다 !!!! 이벤트 핸들링을 폼 대신 패널로 옮겨야했지만 작동했습니다
Justin

54

필요한 것보다 더 어렵게 만들지 맙시다. 양식 (또는 다른 컨트롤)을 드래그 할 수있는 코드 조각이 너무 많습니다. 그리고 그들 중 많은 것들은 그들 자신의 단점 / 부작용을 가지고 있습니다. 특히 폼의 컨트롤이 실제 폼이라고 생각하도록 Windows를 속이는 사람들.

즉, 여기 내 스 니펫이 있습니다. 나는 항상 그것을 사용합니다. 또한 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
dang winforms ... 거의 2 시간 동안이 답변을 찾았습니다.
PrinceOfRavens 2015

이것이 바로 제가 생각한 방식입니다. 내 유일한 문제는 당신이 어떻게했는지 읽을 때까지 지옥처럼 버그가 많았다는 것입니다. 감사 메이트
EasyBB

이것은 오버라이드 WndProc 위의 놀라운 작은 스 니펫보다 나에게 더 잘 작동했습니다. WndProc가 작동했음을 기억하세요. 다른 작업이 중단되었습니다. 감사!
Mmm

잘 작동하고 WndProc에 의존하지 않기 때문에 아마도 최고의 옵션 일 것입니다 (Mono를 사용하여 다른 플랫폼으로 쉽게 이식 할 수 있음). 최대화 / 정상 상태를 변화시킴으로써 향상 될 수있다 Y <10의 경우
Sylverdrag

모노에서는 작동하지 않고 .net 4.5.2를 모노 / 넷 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
두 번 클릭하면 양식이 최대화됩니다. 또한 여기 저기에서 이것이 오른쪽 클릭을 중단한다는 것을 읽으십시오.
Sebastiano

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 이벤트를 생성하는 폼에 의존합니다. 간단한 경우로, 최상위 픽셀 행에서 Form을 그레이딩하고 위쪽으로 드래그한다고 가정합니다. 아무 일도 일어나지 않지만 마우스를 다시 움직이면 양식이 점프합니다.
Joey

12

WPF 만


정확한 코드는 없지만 최근 프로젝트에서는 MouseDown 이벤트를 사용하고 간단히 다음과 같이 입력했다고 생각합니다.

frmBorderless.DragMove();

Window.DragMove 메서드 (MSDN)


2
그래도 WPF입니다. 좋아, OP는 이것을 정확하게 지정하지 않았습니다.
Joey

네, 제가하고있는 프로젝트에 대해 잊었던 것입니다. 방금 Forms를 봤는데 사용할 수 없습니다. 죄송합니다!
Chris

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 문 외에는 아무것도 모릅니다!
Jamshaid Kamran

이것은 WM_NCHITTEST변장입니다.
Andreas Rejbrand

4

이 일이 마술처럼 일어나도록 뒤집을 수있는 속성은 없습니다. 양식에 대한 이벤트를 살펴보면 this.Topthis.Left. 특히 MouseDown, MouseUpMouseMove.


이 이벤트를 사용해야한다고 생각했지만 어떻게해야할지 모르겠습니다. MouseDown 이벤트가 호출 될 때 양식을 이동하려면 어떻게해야합니까?
사용자

1
마우스를 내리면 플래그를 설정하고 기본 좌표를 저장합니다. 마우스 이동시-플래그가 설정된 경우-새 마우스 좌표의 오프셋으로 상단과 왼쪽을 조정합니다. 마우스를 올리면 깃발을 지 웁니다.
Murph

그래도 여전히 마우스 이벤트를받는 것에 의존하지 않는 Windows API를 사용하여이 작업을 수행 할 수 있습니다. 예를 들어 양식의 맨 위 가장자리에있는 픽셀을 잡고 위쪽으로 드래그하면이 방법이 실패합니다.
Joey

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

이것은 당신의 문제를 해결할 수 있습니다 ....


당신은 또한 대신 Control.MousePosition의 "e.Location"를 사용할 수 있습니다
레자 Taibur


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- tour에 오신 것을 환영합니다 . How to Answer 를 확인하세요 . 이 코드가 OP "orginal poster"문제를 어떻게 해결하는지에 대한 설명을 제공해야합니다. 답변을 확인하는 모든 사람에게 더 도움이 될 것입니다.
Mauricio Arias Olave

2

.NET Framework 4의 경우

드래그하는 데 사용하는 구성 요소 (이 예에서는 mainLayout) this.DragMove()MouseDown이벤트에 사용할 수 있습니다 .

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

2

가장 쉬운 방법은 다음과 같습니다.

먼저 label1이라는 레이블을 만듭니다. label1의 이벤트> 마우스 이벤트> Label1_Mouse 이동하여 다음을 작성하십시오.

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

2

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

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양식을 더 크게 / 작게 만드십시오. 또한 매 0.5 초 또는 1 초마다 타이머를 사용하여 variable = 0;


1

MouseLeftButtonDownMainWindow에 이벤트 핸들러를 추가하면 저에게 효과적이었습니다.

자동으로 생성되는 이벤트 함수에 아래 코드를 추가합니다.

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

1

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

0

나는 다음을 시도하고 presto changeo, 내 투명한 창은 더 이상 제자리에 고정되지 않았지만 이동할 수 있습니다! (위의 다른 모든 복잡한 솔루션을 버리십시오 ...)

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

이 답변은 WPF에 대한 것이며 질문은 WinForms에 관한 것입니다.
Ray

0

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

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
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.