マウスがフォーム上でクリックされたときに、境界線があるように境界線のないフォーム(FormBorderStyleが "none"に設定されている)を移動可能にする方法はありますか?
これ 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);
}
}
これは、ウィンドウマネージャーの観点から、ウィンドウのタイトルバーを取得するのと同じexactlyと本質的に同じです。
物事を必要以上に難しくしないようにしましょう。フォーム(または別のコントロール)をドラッグできるようにするコードのスニペットがたくさんあります。そしてそれらの多くには、独自の欠点/副作用があります。特に、フォーム上のコントロールが実際のフォームであるとWindowsを考えさせるもの。
とはいえ、これが私のスニペットです。いつも使っています。また、this.Invalidate();を使用しないでください。他の人が好むように、フォームがちらつく場合があります。また、場合によってはthis.Refreshも行います。 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つの簡単な方法。
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);
}
これを魔法のように実行するために反転できるプロパティはありません。フォームのイベントを見て、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;
}
}
これで問題を解決できます。..
私が見つけた最良の方法(もちろん変更)
// 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);
上記のリンクからのこのコードは、私の場合はうまくいきました:)
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);
}
}
最も簡単な方法は次のとおりです。
まず、label1という名前のラベルを作成します。 label1のイベント>マウスイベント> Label1_Mouseに移動して、これらを記述します。
if (e.Button == MouseButtons.Left){
Left += e.X;
Top += e.Y;`
}
いくつかの回答では子コントロールをドラッグ可能にできないため、小さなヘルパークラスを作成しました。トップレベルのフォームを渡す必要があります。必要に応じて、より汎用的にすることができます。
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);
}
}
}
また、DoubleClickでフォームを大きく/小さくする必要がある場合は、最初の回答を使用し、グローバルint変数を作成し、ドラッグに使用するコンポーネントをクリックするたびに1を追加します。 variable == 2
の場合、フォームを大きく/小さくします。また、0.5秒ごとまたは1秒ごとにタイマーを使用してvariable = 0
を作成します。
WPF Element HostコントロールとWPF Userコントロールを含むボーダーレスウィンドウを移動可能にしようとしていました。
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);
.NET Framework 4の場合
ドラッグに使用しているコンポーネント(この例ではmainLayout)のMouseDown
イベントにthis.DragMove()
を使用できます。
private void mainLayout_MouseDown(object sender, MouseButtonEventArgs e)
{
this.DragMove();
}
MainWindowにMouseLeftButtonDown
イベントハンドラーを追加するとうまくいきました。
自動生成されるイベント関数に、以下のコードを追加します:
base.OnMouseLeftButtonDown(e);
this.DragMove();
以下を試してみましたが、私の透明なウィンドウは固定されていませんが、移動できました!! (上記の他のすべての複雑なソリューションを捨てる...)
private void Window_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
base.OnMouseLeftButtonDown(e);
// Begin dragging the window
this.DragMove();
}
それは私のために働いた。
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);
}
}
Jay_t55からソリューションを拡張するもう1つのメソッド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;
}