Kenarlıksız bir formu taşınabilir hale getirmek mi?


109

Form üzerinde fare tıklandığında, kenarlığı olmayan bir formu (FormBorderStyle "yok" olarak ayarlanmıştır) hareketli hale getirmenin bir yolu var mı?

Yanıtlar:


252

CodeProject hakkındaki bu makale bir tekniği detaylandırmaktadır. Temelde şu şekilde özetlenebilir:

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

Bu , pencere yöneticisinin bakış açısından, bir pencerenin başlık çubuğunu almakla tam olarak aynı şeyi yapar .


Bu benim için hiç çalışmıyor. Kod gayet iyi çalışıyor, her şey doğru ve pencerem hala orada duruyor. Herhangi bir fikir?
dbrree

8
@dbrree Muhtemelen kodu kopyalamışsınızdır Form1_MouseDown, gerçek MouseDownolayına atanmadığı için çalışmaz Form1.
Remon Ramy

2
Formu sürüklemek için tuttuğunuz bir etiketiniz veya simgeniz (veya diğer ön plandaki nesneler!) Varsa, bu öğelere de bir fare indirme olayı ekleyin. Form olayları, form nesnelerinin arkasını göremez.
Paul Nelson

1
Form this.MouseDown += ...için Main()işleve eklemeniz gerekiyor
Richard Peck

1
Benim için bir cazibe gibi çalıştı !!!! Olay yönetimini formun yerine koyduğum panele taşımak zorunda kaldım ama işe yaradı
Justin

54

İşleri olması gerekenden daha zor hale getirmeyelim. Bir formu (veya başka bir Kontrolü) sürüklemenize izin veren çok sayıda kod parçacığı ile karşılaştım. Ve birçoğunun kendi dezavantajları / yan etkileri vardır. Özellikle Windows'u bir form üzerindeki Kontrolün gerçek form olduğunu düşünmesi için kandırdıkları kişiler.

Olduğu söyleniyor, işte benim pasajım. Ben her zaman kullanırım. Ayrıca bunu kullanmamanız gerektiğini de not etmek isterim.Invalidate (); Bazı durumlarda formun titremesine neden olduğu için diğerleri yapmaktan hoşlanır. Ve bazı durumlarda bunu yapar. Bunu kullanarak Güncelle, titreyen herhangi bir sorun yaşamadım:

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 ... bu cevabı neredeyse iki saat aradım .... c # için yeniyim, yine de bana harikalar yarattın!
PrinceOfRavens

Bu tam olarak düşündüğüm yol, tek sorunum, nasıl yaptığını okuyana kadar cehennem kadar hatalı olmasıydı. Teşekkürler dostum
EasyBB

Bu, benim için WndProc geçersiz kılmalarının üzerindeki harika minik parçacığından daha iyi çalıştı. Unutmayın, WndProc işe ​​yaradı ... sadece diğer şeylerin çalışmasını engelledi. Teşekkürler!
Mmm

Muhtemelen burada güzel çalıştığı ve WndProc'a dayanmadığı için en iyi seçenek (Mono ile diğer platformlara kolayca taşınabilir). Y <10
Sylverdrag

Mono üzerinde çalışmıyor, .net 4.5.2'yi mono / net 4.5 olarak değiştirdi ve hala çalışmıyor. Şimdi bir çözüm bulmaya çalışıyorum.
Roger Derin

35

Aynı şeyi yapmanın başka bir basit yolu.

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
Belirli bir aracı (örneğin bir etiket) tutarak formu taşıyabilmenizi mümkün kılan herhangi biri.
Thomas W

2
Çift tıklandığında form büyütülür. Ayrıca burada ve orada bunun sağ tıklamayı bozduğunu okuyun.
Sebastiano

19

MouseDown, MouseMove ve MouseUp'ı kullanın. Bunun için değişken bir bayrak ayarlayabilirsiniz. Bir örneğim var, ama revize etmeniz gerektiğini düşünüyorum.

Fare eylemini bir panele kodluyorum. Paneli tıkladığınızda, formunuz onunla birlikte hareket edecektir.

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

Bu. Zaten başka bir yerde de söylendiği gibi, bu hala MouseMove olayları oluşturan forma dayanmaktadır. Basit bir durum olarak, Formu en üstteki piksel satırından derecelendirdiğinizi ve yukarı doğru sürüklediğinizi varsayalım. Form, fareyi tekrar üzerine getirdiğiniz anda etrafta dolanmasına rağmen, hiçbir şey olmayacak.
Joey

13

Yalnızca WPF


Elde edilecek tam kod yok, ancak son projede MouseDown olayını kullandığımı ve basitçe şunu koyduğumu düşünüyorum:

frmBorderless.DragMove();

Window.DragMove Yöntemi (MSDN)


2
Yine de bu WPF. Tamam, OP bunu tam olarak belirtmedi.
Joey

Evet, yaptığım proje hakkında unuttuğum bir şey. Formlar'a baktım ve mevcut değil. Afedersiniz!
Chris

3
@Chris Bu benim için bir WPF projesinde çalıştı. Cevabı silmediğiniz için teşekkürler.
Rembunator

7

Ref. Video bağlantısı

Bu test edilmiştir ve anlaşılması kolaydır.

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
Bu kod işe yarıyor, ancak anlaşılması nasıl kolay? Bu kod segmentinde switch ifadesinden başka hiçbir şey bilmiyorum!
Jamshaid Kamran

Bu WM_NCHITTESTkılık değiştirmiş.
Andreas Rejbrand

4

Bunun sihirli bir şekilde gerçekleşmesi için çevirebileceğiniz hiçbir özellik yok. Form için olaylara bakın ve bunu this.Topve ayarlayarak uygulamak oldukça önemsiz hale geliyor this.Left. Özellikle bakmak isteyeceksiniz MouseDown, MouseUpve MouseMove.


Bu olayları kullanmam gerektiğini düşündüm ama onlarla ne yapacağımdan emin değilim. MouseDown olayı çağrıldığında, formun taşınmasına nasıl izin verebilirim?
kullanıcı

1
Fare aşağıdayken bir bayrak belirler ve temel koordinatları kaydedersiniz. Fare hareketinde - eğer bayrak ayarlanmışsa - üst ve solu yeni fare koordinatlarının ofsetiyle ayarlarsınız. Fare yukarı kalktığında bayrağı temizlersiniz.
Murph

Yine de, bunu Windows API ile oldukça kolay bir şekilde yapabilirsiniz; bu, hala fare olaylarını almaya bağlı değildir. Örneğin, formun en üst kenarındaki bir pikseli tutup yukarı doğru sürüklerseniz bu yöntem başarısız olur.
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;
  }
}

bu senin problemini çözebilir ....


Control.MousePosition yerine "e.Location" da kullanabilirsiniz
Reza Taibur


4

Bulduğum en iyi yol (elbette değiştirildi)

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

Bir kontrole sürükleme uygulamak için bunu InitializeComponent () sonrasına eklemeniz yeterlidir.

AddDrag(NameOfControl);

4

Benim için çalıştı.

    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'a hoş geldiniz - tur , lütfen Nasıl Cevaplanacağını kontrol edin . Bu kodun OP "orjinal poster" problemini nasıl çözdüğüne dair bir açıklama sağlamalısınız. Cevabınızı kontrol eden herkes için daha yararlı olacaktır.
Mauricio Arias Olave

2

.NET Framework 4 için,

Sürüklemek için kullandığınız bileşenin (bu örnekte mainLayout) olayı this.DragMove()için kullanabilirsiniz MouseDown.

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

2

En kolay yol:

Önce label1 adında bir etiket oluşturun. Label1 olayları> mouse olayları> Label1_Mouse Move seçeneğine gidin ve şunları yazın:

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

2

Bir WPF Element Host kontrolü ve bir WPF Kullanıcı kontrolü içeren hareketli bir kenarlıksız pencere formu oluşturmaya çalışıyordum.

WPF kullanıcı kontrolümde StackPanel adında bir yığın paneli buldum, bu da hareket etmek için tıklamayı denemek için mantıklı bir şey gibi görünüyordu. Fareyi yavaşça hareket ettirdiğimde junmats kodunu denemek işe yaradı, ancak fareyi daha hızlı hareket ettirirsem, fare formdan çıkacak ve form, hareketin ortasında bir yere sıkışacaktı.

Bu, CaptureMouse ve ReleaseCaptureMouse kullanarak durumum için verdiği yanıtta gelişti ve şimdi hızlı hareket etsem bile fare, onu hareket ettirirken formdan çıkmıyor.

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

Bazı cevaplar çocuk kontrollerinin sürüklenebilir olmasına izin vermediğinden, küçük bir yardımcı sınıf oluşturdum. Üst düzey formdan geçilmelidir. İstenirse daha jenerik yapılabilir.

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

Ayrıca DoubleClick'e ihtiyacınız varsa ve Formunuzu büyütmeniz / küçültmeniz gerekiyorsa, İlk yanıtı kullanabilir, bir global int değişkeni oluşturabilir, kullanıcı sürüklemek için kullandığınız bileşene her tıkladığında 1 ekleyebilirsiniz. Eğer variable == 2o zaman daha küçük / formunuz büyük yapmak. Ayrıca, her yarım saniye veya saniyede bir zamanlayıcı kullanarak variable = 0;


1

MouseLeftButtonDownMainWindow'a bir olay işleyicisi eklemek benim için çalıştı.

Otomatik olarak oluşturulan olay işlevinde aşağıdaki kodu ekleyin:

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

1

Jay_t55'teki çözümü ToolStrip1_MouseLeave, farenin hızlı hareket etmesi ve bölgeden ayrılması olayını işleyen bir yöntemle genişletiyorum .

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

Aşağıdakini denedim ve değiştirmeye çalıştım, şeffaf pencerem artık yerinde donmuştu ama hareket ettirilebilirdi !! (yukarıdaki diğer tüm karmaşık çözümleri atın ...)

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

Bu cevap WPF için, soru WinForms ile ilgili.
Ray

0

Form1 (): new Moveable(control1, control2, control3);

Sınıf:

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

Cevabınızı bazı açıklamalarla desteklerseniz güzel olur :)
Mustafamg
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.