I have a windows form without title bar. I want to drag it by mouse. After searching on internet, I found this code for moving form:
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);
}
But it has a problem: It operates only on form regions which are not covered by any control. For example if I use label or group box, I can't move form by clicking on them.
How can I solve this problem?
One way is to implement IMessageFilter like this.
public class MyForm : Form, IMessageFilter
{
public const int WM_NCLBUTTONDOWN = 0xA1;
public const int HT_CAPTION = 0x2;
public const int WM_LBUTTONDOWN = 0x0201;
[DllImportAttribute("user32.dll")]
public static extern int SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam);
[DllImportAttribute("user32.dll")]
public static extern bool ReleaseCapture();
private HashSet<Control> controlsToMove = new HashSet<Control>();
public MyForm()
{
Application.AddMessageFilter(this);
controlsToMove.Add(this);
controlsToMove.Add(this.myLabel);//Add whatever controls here you want to move the form when it is clicked and dragged
}
public bool PreFilterMessage(ref Message m)
{
if (m.Msg == WM_LBUTTONDOWN &&
controlsToMove.Contains(Control.FromHandle(m.HWnd)))
{
ReleaseCapture();
SendMessage(this.Handle, WM_NCLBUTTONDOWN, HT_CAPTION, 0);
return true;
}
return false;
}
}
This is basically what you are looking to do:
Make a borderless form movable?
You might be able to add the same code to the mouse down event of other controls on your form to accomplish the same thing.
Make a borderless form movable?
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 Form1_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
ReleaseCapture();
SendMessage(Handle, WM_NCLBUTTONDOWN, HT_CAPTION, 0);
}
}
When the user presses the mouse down over the lblMoveForm Label in the form, the following event handler executes.
// On left button, let the user drag the form.
private void lblMoveForm_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
// Release the mouse capture started by the mouse down.
lblMoveForm.Capture = false; //select control
// Create and send a WM_NCLBUTTONDOWN message.
const int WM_NCLBUTTONDOWN = 0x00A1;
const int HTCAPTION = 2;
Message msg =
Message.Create(this.Handle, WM_NCLBUTTONDOWN,
new IntPtr(HTCAPTION), IntPtr.Zero);
this.DefWndProc(ref msg);
}
}
//For base form moving
private const int HT_CAPTION = 0x2;
private const int WM_NCHITTEST = 0x84;
private const int HT_CLIENT = 0x1;
protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
if (m.Msg == WM_NCHITTEST)
m.Result = (IntPtr)(HT_CAPTION);
}
//For any component you also want use to move form
private bool arrastando= false;
private Point pontoinicial= new Point(0,0);
private Point meu_offset;
//use this method for component event called MouseDown
private void dragMouseDown(object sender, MouseEventArgs e)
{
arrastando = true;
pontoinicial = new Point(e.X, e.Y);
}
//use this method for component event called MouseUp
private void dragMouseUp(object sender, MouseEventArgs e)
{
arrastando=false;
}
//use this method for component event called MouseMove
private void dragMouseMove(object sender, MouseEventArgs e)
{
if (arrastando)
{
Point p = PointToScreen(e.Location);
ActiveForm.Location = new Point(p.X - this.pontoinicial.X,
p.Y - this.pontoinicial.Y);
}
}
Related
not sure i explained it well in the title;
if youre on windows, click and drag on the title bar of FireFox/Chrome/other application and drag it to the top or side of the screen. it creates a weird effect and when u release the capture, depending on where you dragged it, it will either maximize or split the screen.
when i use App.FormBorderStyle = FormBorderStyle.None; it doesnt give me the split/max effect when i drag it to top. i have enabled drag by:
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();
// this is the panel i use as a title bar for dragging
private void panel1_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
ReleaseCapture();
SendMessage(Handle, WM_NCLBUTTONDOWN, HT_CAPTION, 0);
}
}
now, how can i enable this feature of dragging to the top of screen and having windows display the effect of max/split.
thank you.
Maybe you can try to achieve them by determining the location of the form based on Location.X and Location.Y .
Here is a demo you can refer to.
public Form1()
{
InitializeComponent();
this.FormBorderStyle = FormBorderStyle.None;
}
// Save original size
Size original;
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, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
ReleaseCapture();
SendMessage(Handle, WM_NCLBUTTONDOWN, HT_CAPTION, 0);
// Drag to top to maximize
if (this.Location.Y <= 0)
{
this.WindowState = FormWindowState.Maximized;
}
else
{
this.Size = original;
}
// Drag to side to split screen
if (this.Location.X <= 0)
{
this.Location = new Point(0, 0);
this.Size = new Size(SystemInformation.WorkingArea.Width / 2, SystemInformation.WorkingArea.Height);
}
else if (this.Location.X >= SystemInformation.WorkingArea.Width / 2)
{
this.Location = new Point(SystemInformation.WorkingArea.Width / 2, 0);
this.Size = new Size(SystemInformation.WorkingArea.Width / 2, SystemInformation.WorkingArea.Height);
}
else
{
this.Size = original;
}
}
}
private void Form1_Load(object sender, EventArgs e)
{
original = this.Size;
}
I've made a circle shaped movable form using the code in the following link
Make a borderless form movable?
this Code:
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 Form1_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
ReleaseCapture();
SendMessage(Handle, WM_NCLBUTTONDOWN, HT_CAPTION, 0);
}
}
Now my form is moving as I wanted but I want to add a click event to that form, but click event isn't firing. Can anyone tell what I'm missing?
Note: I just want to call a function whenever someone clicks my form.
You can use the MouseMove method instead of the MouseDown method:
protected override void OnMouseMove(MouseEventArgs e) {
base.OnMouseMove(e);
if (e.Button == MouseButtons.Left) {
ReleaseCapture();
SendMessage(Handle, WM_NCLBUTTONDOWN, HT_CAPTION, 0);
}
}
protected override void OnClick(EventArgs e) {
base.OnClick(e);
MessageBox.Show("Clicked");
}
A form does not have to listen to their own events, so I am just overriding the MouseMove and Click procedures in the code above.
I try to configure some global Hotkeys in a C# WinForm Application that should work with and without focus. For this I played a little bit with some Hooking Librarys like: Link
But these Libraries are not working really reliable so that I decided to look for a different way. And I found one but there is one problem: With the new method posted below I can catch a keypress, but I like to catch also the keydown (WM_KEYDOWN/0x100) and keyup event... But this is not working. Any ideas?
Code:
public Form1()
{
InitializeComponent();
}
[DllImport("user32.dll")]
private static extern bool RegisterHotKey(IntPtr hWnd, int id, int fsModifiers, int vk);
[DllImport("user32.dll")]
private static extern bool UnregisterHotKey(IntPtr hWnd, int id);
const int MOD_CONTROL = 0x0002;
const int MOD_SHIFT = 0x0004;
const int WM_HOTKEY = 0x0312;
const int WM_KEYDOWN = 0x0100;
private void Form1_Load(object sender, EventArgs e)
{
// Hook Keys
RegisterHotKey(this.Handle, 1, MOD_CONTROL, (int)0);
RegisterHotKey(this.Handle, 2, MOD_CONTROL, (int)Keys.X);
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
UnregisterHotKey(this.Handle, 1);
}
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_HOTKEY && (int)m.WParam == 1)
{
MessageBox.Show("here");
}
if (m.Msg == WM_KEYDOWN && (int)m.WParam == 2)
this.Opacity = 100;
base.WndProc(ref m);
}
I have a WinForms project. I have a panel on the top of my window. I want that panel to be able to move the window, when the user clicks on it and then drags.
How can I do this?
Add the following declerations to your class:
public const int WM_NCLBUTTONDOWN = 0xA1;
public const int HTCAPTION = 0x2;
[DllImport("User32.dll")]
public static extern bool ReleaseCapture();
[DllImport("User32.dll")]
public static extern int SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam);
Put this in your panel's MouseDown event:
private void panel1_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
ReleaseCapture();
SendMessage(Handle, WM_NCLBUTTONDOWN, HTCAPTION, 0);
}
}
I have a form created in Windows Forms which is draggable wherever I click. I made it by overriding WndProc function which in turn modifies each click as it was a title bar click:
//found at: http://stackoverflow.com/questions/3995009/how-to-make-a-window-draggablec-winforms
private const int WM_NCHITTEST = 0x84;
private const int HTCLIENT = 0x1;
private const int HTCAPTION = 0x2;
///
/// Handling the window messages
///
protected override void WndProc(ref Message message)
{
base.WndProc(ref message);
if (message.Msg == WM_NCHITTEST && (int)message.Result == HTCLIENT)
message.Result = (IntPtr)HTCAPTION;
}
The problem is that now when I double click, the window becomes fullscreen, which is unwanted. How can I block this behavior?
In addition to JaredPar I would suggest don not create draggable form in that way, but handle it in 3 steps
identify mouse down on the form
capture mouse
identify mouse up event
It is not a complicated to handle, and it's better, imo, then disabling a double click on the form.
For complete example of how you can do that can have a look on
Creating a Draggable Borderless Form
I was having the same problem today in C++. I used JaredPar's solution but with WM_NCLBUTTONDBLCLK (0x00A3) instead of WM_LBUTTONDBLCLK, that did the trick for me! It's working because the double click message is being sent from a non-client (NC) area, which is the "virtual" title bar (HTCAPTION) in this case.
I've done the same as Jex which is working great.
private const int WM_NCHITTEST = 0x84;
private const int HTCLIENT = 0x1;
private const int HTCAPTION = 0x2;
private const int WM_LBUTTONDBLCLK = 0x00A3;
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_LBUTTONDBLCLK)
{
return;
}
switch (m.Msg)
{
case WM_NCHITTEST:
base.WndProc(ref m);
if ((int)m.Result == HTCLIENT)
m.Result = (IntPtr)HTCAPTION;
return;
}
base.WndProc(ref m);
}
It seems you found a solution to a problem with caused another problem that you're trying to solve. If I could suggest something simple, just a better solution to make a window drag-able:
Add InteropServices to the using declarations:
using System.Runtime.InteropServices;
And for the code:
public const int WM_NCLBUTTONDOWN = 0xA1;
public const int HT_CAPTION = 0x2;
[DllImportAttribute("user32.dll")]
public static extern int SendMessage(IntPtr hWnd,
int Msg, int wParam, int lParam);
[DllImportAttribute("user32.dll")]
public static extern bool ReleaseCapture();
Then go to the form's MouseDown event and paste this:
if (e.Button == MouseButtons.Left)
{
ReleaseCapture();
SendMessage(Handle, WM_NCLBUTTONDOWN, HT_CAPTION, 0);
}
Done.
If you just want to stop the double click from having it's default behavior in the window for which you've overridden the WndProc then intercept the WM_LBUTTONDBLCLK message
private const int WM_LBUTTONDBLCLK = 0x0203;
...
protected override void WndProc(ref Message message) {
if (message.Msg == WM_LBUTTONDBLCLK) {
return;
}
base.WndProc(ref message);
if (message.Msg == WM_NCHITTEST && (int)message.Result == HTCLIENT)
message.Result = (IntPtr)HTCAPTION;
}