답변:
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);
}
}
이것은 기본적으로 창 관리자의 관점에서 창의 제목 표시 줄을 잡는 것과 똑같 습니다.
Form1_MouseDown
의 실제 MouseDown
이벤트에 할당 되지 않았으므로 작동하지 않는 코드를 복사했을 것 입니다 Form1
.
this.MouseDown += ...
받는 Main()
폼의 기능
필요한 것보다 더 어렵게 만들지 맙시다. 양식 (또는 다른 컨트롤)을 드래그 할 수있는 코드 조각이 너무 많습니다. 그리고 그들 중 많은 것들은 그들 자신의 단점 / 부작용을 가지고 있습니다. 특히 폼의 컨트롤이 실제 폼이라고 생각하도록 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;
}
동일한 작업을 수행하는 또 다른 간단한 방법입니다.
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;
}
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);
}
}
WPF 만
정확한 코드는 없지만 최근 프로젝트에서는 MouseDown 이벤트를 사용하고 간단히 다음과 같이 입력했다고 생각합니다.
frmBorderless.DragMove();
이것은 테스트를 거쳐 이해하기 쉽습니다.
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);
}
WM_NCHITTEST
변장입니다.
이 일이 마술처럼 일어나도록 뒤집을 수있는 속성은 없습니다. 양식에 대한 이벤트를 살펴보면 this.Top
및 this.Left
. 특히 MouseDown
, MouseUp
및 MouseMove
.
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;
}
}
이것은 당신의 문제를 해결할 수 있습니다 ....
위 링크의이 코드는 제 경우에는 트릭을했습니다. :)
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);
}
}
내가 찾은 가장 좋은 방법 (물론 수정)
// 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);
그것은 나를 위해 일했습니다.
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);
}
}
.NET Framework 4의 경우
드래그하는 데 사용하는 구성 요소 (이 예에서는 mainLayout) this.DragMove()
의 MouseDown
이벤트에 사용할 수 있습니다 .
private void mainLayout_MouseDown(object sender, MouseButtonEventArgs e)
{
this.DragMove();
}
가장 쉬운 방법은 다음과 같습니다.
먼저 label1이라는 레이블을 만듭니다. label1의 이벤트> 마우스 이벤트> Label1_Mouse 이동하여 다음을 작성하십시오.
if (e.Button == MouseButtons.Left){
Left += e.X;
Top += e.Y;`
}
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);
일부 답변은 자식 컨트롤을 드래그 할 수 없도록하기 때문에 약간의 도우미 클래스를 만들었습니다. 최상위 양식을 전달해야합니다. 원하는 경우 더 일반적으로 만들 수 있습니다.
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);
}
}
}
MouseLeftButtonDown
MainWindow에 이벤트 핸들러를 추가하면 저에게 효과적이었습니다.
자동으로 생성되는 이벤트 함수에 아래 코드를 추가합니다.
base.OnMouseLeftButtonDown(e);
this.DragMove();
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;
}
나는 다음을 시도하고 presto changeo, 내 투명한 창은 더 이상 제자리에 고정되지 않았지만 이동할 수 있습니다! (위의 다른 모든 복잡한 솔루션을 버리십시오 ...)
private void Window_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
base.OnMouseLeftButtonDown(e);
// Begin dragging the window
this.DragMove();
}
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; }
}
};
}
}
}
[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);
}