Existe uma maneira de tornar um formulário sem borda (FormBorderStyle definido como "nenhum") móvel quando o mouse é clicado no formulário como se houvesse uma borda?
Existe uma maneira de tornar um formulário sem borda (FormBorderStyle definido como "nenhum") móvel quando o mouse é clicado no formulário como se houvesse uma borda?
Respostas:
Este artigo em CodeProject detalha uma técnica. Basicamente se resume a:
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);
}
}
Isso basicamente faz exatamente o mesmo que pegar a barra de título de uma janela, do ponto de vista do gerenciador de janelas.
Form1_MouseDown
não está atribuído ao MouseDown
evento real de Form1
.
this.MouseDown += ...
à Main()
função para o formulário
Não vamos tornar as coisas mais difíceis do que precisam ser. Eu encontrei tantos trechos de código que permitem que você arraste um formulário (ou outro controle). E muitos deles têm suas próprias desvantagens / efeitos colaterais. Especialmente aqueles em que enganam o Windows fazendo-o pensar que um controle em um formulário é o formulário real.
Dito isso, aqui está o meu trecho. Eu uso isso o tempo todo. Também gostaria de observar que você não deve usar this.Invalidate (); como outros gostam de fazer porque faz com que o formulário pisque em alguns casos. E em alguns casos isso acontece. Usando this.Update, não tive problemas de oscilação:
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;
}
Outra maneira mais simples de fazer a mesma coisa.
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;
}
use MouseDown, MouseMove e MouseUp. Você pode definir um sinalizador de variável para isso. Eu tenho uma amostra, mas acho que você precisa revisar.
Estou codificando a ação do mouse em um painel. Depois de clicar no painel, seu formulário será movido com ele.
//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 apenas
não tenho o código exato em mãos, mas em um projeto recente, acho que usei o evento MouseDown e simplesmente coloquei isto:
frmBorderless.DragMove();
Isso é testado e fácil de entender.
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
disfarçado.
Não há propriedade que você possa alterar para fazer isso acontecer magicamente. Observe os eventos do formulário e torna-se bastante trivial implementar isso definindo this.Top
e this.Left
. Especificamente você vai querer olhar para MouseDown
, MouseUp
e 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;
}
}
isso pode resolver seu problema ....
Este trecho de código do link acima funcionou no meu caso :)
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);
}
}
Melhor maneira que encontrei (modificada, é claro)
// 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; }
}
}
Para aplicar o arrasto a um controle, basta inseri-lo após InitializeComponent ()
AddDrag(NameOfControl);
Funcionou para mim.
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);
}
}
Para .NET Framework 4,
Você pode usar this.DragMove()
para o MouseDown
evento do componente (mainLayout neste exemplo) que você está usando para arrastar.
private void mainLayout_MouseDown(object sender, MouseButtonEventArgs e)
{
this.DragMove();
}
A maneira mais fácil é:
Primeiro crie um rótulo denominado label1. Vá para eventos de label1> eventos de mouse> Label1_Mouse Move e escreva estes:
if (e.Button == MouseButtons.Left){
Left += e.X;
Top += e.Y;`
}
Eu estava tentando fazer um formulário de janelas sem borda móvel que continha um controle de host de elemento WPF e um controle de usuário WPF.
Acabei com um painel de pilha chamado StackPanel em meu controle de usuário WPF que parecia a coisa lógica para tentar clicar para mover. Tentar o código do junmats funcionou quando movi o mouse lentamente, mas se movesse o mouse mais rápido, o mouse se moveria para fora do formulário e o formulário ficaria preso em algum lugar no meio do movimento.
Isso melhorou sua resposta para a minha situação usando CaptureMouse e ReleaseCaptureMouse e agora o mouse não se move para fora do formulário enquanto o move, mesmo que eu o mova rapidamente.
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);
Como algumas respostas não permitem que os controles filhos sejam arrastáveis, criei uma pequena classe auxiliar. Deve ser passado o formulário de nível superior. Pode ser mais genérico, se desejado.
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);
}
}
}
Além disso, se precisar fazer o DoubleClick e tornar seu formulário maior / menor, você pode usar a primeira resposta, criar uma variável int global, adicionar 1 sempre que o usuário clicar no componente que você usa para arrastar. Em variable == 2
seguida, torne seu formulário maior / menor. Use também um cronômetro a cada meio segundo ou segundo para fazer o seu variable = 0
;
Adicionar um MouseLeftButtonDown
manipulador de eventos à MainWindow funcionou para mim.
Na função de evento que é gerada automaticamente, adicione o código abaixo:
base.OnMouseLeftButtonDown(e);
this.DragMove();
Estou expandindo a solução de jay_t55 com mais um método ToolStrip1_MouseLeave
que trata o evento do mouse se movendo rapidamente e saindo da região.
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;
}
Eu tentei o seguinte e pronto, minha janela transparente não estava mais congelada no lugar, mas podia ser movida !! (jogue fora todas as outras soluções complexas acima ...)
private void Window_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
base.OnMouseLeftButtonDown(e);
// Begin dragging the window
this.DragMove();
}
Formulário 1(): new Moveable(control1, control2, control3);
Classe:
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);
}