Zrobić ruchomy formularz bez obramowania?

109

Czy istnieje sposób, aby formularz, który nie ma obramowania (FormBorderStyle jest ustawiony na „brak”), byłby ruchomy po kliknięciu myszą na formularzu, tak jakby istniała ramka?

użytkownik
źródło

Odpowiedzi:

252

W tym artykule na CodeProject opisano szczegółowo technikę. Zasadniczo sprowadza się do:

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

Zasadniczo robi to dokładnie to samo, co chwytanie paska tytułu okna, z punktu widzenia menedżera okien.

Joey
źródło
Na mnie to w ogóle nie działa. Kod działa dobrze, wszystko jest poprawne, a moje okno nadal tam siedzi. Jakieś pomysły?
dbrree
8
@dbrree Prawdopodobnie skopiowałeś kod, który nie będzie działał, ponieważ Form1_MouseDownnie jest przypisany do rzeczywistego MouseDownzdarzenia Form1.
Remon Ramy,
2
Jeśli masz etykietę lub ikonę (lub jakiekolwiek inne obiekty na pierwszym planie!), W których chwytasz formularz do przeciągnięcia, dodaj zdarzenie przesunięcia kursora również do tych elementów. Zdarzenia formularzy nie widzą przez obiekty formularzy.
Paul Nelson,
1
Musisz dodać this.MouseDown += ...do Main()funkcji formularza
Richard Peck
1
U mnie zadziałało jak urok !!!! Musiałem przenieść obsługę zdarzenia do panelu, który wstawiałem w miejsce formularza, ale zadziałało
Justin,
54

Nie róbmy rzeczy trudniejszych niż to konieczne. Natknąłem się na tak wiele fragmentów kodu, które pozwalają przeciągać formularz (lub inną kontrolkę). Wiele z nich ma swoje wady / skutki uboczne. Szczególnie te, w których oszukują system Windows, aby pomyślał, że kontrolka w formularzu jest rzeczywistą formą.

Biorąc to pod uwagę, oto mój fragment. Używam go cały czas. Chciałbym również zauważyć, że nie powinieneś używać this.Invalidate (); jak lubią to robić inni, ponieważ w niektórych przypadkach powoduje to migotanie formularza. A w niektórych przypadkach tak się dzieje. Używając this.Update, nie miałem żadnych problemów z migotaniem:

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;
    }
jay_t55
źródło
1
dang winforms ... szukałem tej odpowiedzi przez prawie dwie godziny ... jestem nowy w c # chociaż, zdziałałeś cuda!
PrinceOfRavens
Dokładnie tak myślałem, moim jedynym problemem było to, że był to buggy jak diabli, dopóki nie przeczytałem, jak to zrobiłeś. Dzięki kolego
EasyBB
Ten działał lepiej dla mnie niż niesamowity mały fragment nad zastąpieniami WndProc. Pamiętaj, że WndProc zadziałał ... po prostu zatrzymał inne rzeczy. Dzięki!
Mmm
Prawdopodobnie najlepsza opcja tutaj, ponieważ działa ładnie i nie polega na WndProc (można go łatwo przenieść na inne platformy z Mono). Można poprawić, zmieniając stan na zmaksymalizowany / normalny, jeśli Y <10
Sylverdrag,
Nie działa na mono, zmieniłem .net 4.5.2 na mono / net 4.5 i nadal nie działa. Próbuję teraz znaleźć rozwiązanie.
Roger Deep,
35

Kolejny prostszy sposób na zrobienie tego samego.

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;
}
elimad
źródło
1
Każdy, kto umożliwia przesuwanie formularza, trzymając określone narzędzie (np. Etykietę).
Thomas W,
2
Dwukrotne kliknięcie powoduje zmaksymalizowanie formularza. Przeczytaj także tu i tam, że to przerywa kliknięcie prawym przyciskiem myszy.
Sebastiano
19

użyj MouseDown, MouseMove i MouseUp. Możesz ustawić w tym celu flagę zmiennej. Mam próbkę, ale myślę, że musisz powtórzyć.

Koduję działanie myszy do panelu. Po kliknięciu panelu formularz przesunie się wraz z nim.

//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);     
  }
}
Junmats
źródło
To jest. Jak już wspomniano w innym miejscu, zależy to od formularza, który nadal generuje zdarzenia MouseMove. W prostym przypadku załóżmy, że gradujesz formularz w najwyższym wierszu pikseli i przeciągasz w górę. Nic się nie stanie, chociaż forma będzie podskakiwać, gdy tylko najedziesz na nią myszą.
Joey
12

Tylko WPF


nie mam pod ręką dokładnego kodu, ale myślę, że w ostatnim projekcie użyłem zdarzenia MouseDown i po prostu umieściłem to:

frmBorderless.DragMove();

Metoda Window.DragMove (MSDN)

Chris
źródło
2
To jest jednak WPF. Ok, OP nie określa tego dokładnie.
Joey
Tak, zapomniałem o projekcie, który robiłem. Właśnie spojrzałem na Formularze i nie są one dostępne. Przepraszam!
Chris
3
@Chris To zadziałało dla mnie w projekcie WPF. Dzięki, że nie usuwałeś odpowiedzi.
Rembunator
7

Nr ref. link do filmu

Jest to sprawdzone i łatwe do zrozumienia.

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);
}
Gnana Akilan
źródło
6
Ten kod działa, ale jak łatwo go zrozumieć? Nie wiem nic w tym segmencie kodu poza instrukcją switch!
Jamshaid Kamran
To jest WM_NCHITTESTw przebraniu.
Andreas Rejbrand
4

Nie ma właściwości, które można odwrócić, aby stało się to magicznie. Spójrz na zdarzenia dla formularza i wdrożenie tego przez ustawienie this.Topi this.Left. W szczególności warto przyjrzeć się MouseDown, MouseUpi MouseMove.

Matthew Scharley
źródło
Pomyślałem, że będę musiał wykorzystać te zdarzenia, ale nie jestem pewien, co z nimi zrobić. Kiedy wywoływane jest zdarzenie MouseDown, jak zezwolić na przeniesienie formularza?
użytkownik
1
Po naciśnięciu przycisku myszy ustawiasz flagę i zapisujesz współrzędne bazy. Podczas ruchu myszy - jeśli flaga jest ustawiona - dostosowujesz górę i lewo o przesunięcie nowych współrzędnych myszy. Myszką w górę usuwasz flagę.
Murph
Mimo to można to zrobić dość łatwo za pomocą interfejsu API systemu Windows, co nie zależy od ciągłego otrzymywania zdarzeń myszy. Ta metoda zawodzi, jeśli na przykład złapiesz piksel na samej górnej krawędzi formularza i przeciągniesz w górę.
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;
  }
}

to może rozwiązać twój problem ....

Syed Ali
źródło
Można również użyć „e.Location” zamiast Control.MousePosition
Reza Taibur
4

Najlepszy sposób, jaki znalazłem (oczywiście zmodyfikowany)

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

Aby zastosować przeciąganie do kontrolki, po prostu wstaw to po InitializeComponent ()

AddDrag(NameOfControl);
Ricky Divjakovski
źródło
4

To zadziałało dla mnie.

    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);
        }
    }
Sudhananda Biswas
źródło
Witamy w Stack Overflow - prezentacja , sprawdź, jak odpowiedzieć . Musisz podać wyjaśnienie, w jaki sposób ten kod rozwiązuje problem „oryginalnego plakatu” PO. Będzie to bardziej pomocne dla każdego, kto sprawdzi Twoją odpowiedź.
Mauricio Arias Olave
2

W przypadku .NET Framework 4

Możesz użyć this.DragMove()dla MouseDownzdarzenia składnika (w tym przykładzie mainLayout), którego używasz do przeciągania.

private void mainLayout_MouseDown(object sender, MouseButtonEventArgs e)
{
    this.DragMove();
}
Neeraj Kumar Das
źródło
2

Najłatwiej jest:

Najpierw utwórz etykietę o nazwie label1. Przejdź do zdarzeń label1> zdarzenia myszy> Label1_Mouse Move i napisz te:

if (e.Button == MouseButtons.Left){
    Left += e.X;
    Top += e.Y;`
}
user7500524
źródło
2

Próbowałem zrobić ruchomy formularz okna bez obramowania, który zawiera kontrolkę hosta elementu WPF i kontrolkę użytkownika WPF.

Skończyło się na panelu stosu o nazwie StackPanel w mojej kontrolce użytkownika WPF, który wydawał się logiczną rzeczą, aby spróbować kliknąć, aby przenieść. Wypróbowanie kodu junmats działało, gdy poruszałem myszą powoli, ale jeśli poruszałem myszą szybciej, mysz odsuwałaby się od formularza, a forma utknęłaby gdzieś w połowie ruchu.

To poprawiło jego odpowiedź dla mojej sytuacji przy użyciu CaptureMouse i ReleaseCaptureMouse, a teraz mysz nie odsuwa się od formularza podczas przenoszenia go, nawet jeśli poruszam się szybko.

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);
Mike Sage
źródło
2

Ponieważ niektóre odpowiedzi nie pozwalają na przeciąganie kontrolek podrzędnych, stworzyłem małą klasę pomocniczą. Należy przejść formularz najwyższego poziomu. W razie potrzeby można uczynić bardziej ogólnym.

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);
        }
    }
}
Sebastian
źródło
1

Jeśli chcesz skorzystać z DoubleClick i powiększyć / pomniejszyć swój formularz, możesz użyć pierwszej odpowiedzi, utworzyć globalną zmienną int i dodać 1 za każdym razem, gdy użytkownik kliknie komponent, którego używasz do przeciągania. Jeśli variable == 2więc powiększ / pomniejsz swoją formę. Użyj również timera co pół sekundy lub sekundy, aby zrobić variable = 0;

Billy Xd
źródło
1

Dodanie programu MouseLeftButtonDownobsługi zdarzeń do MainWindow zadziałało dla mnie.

W funkcji zdarzenia, która jest generowana automatycznie, dodaj poniższy kod:

base.OnMouseLeftButtonDown(e);
this.DragMove();
Aparna Ratheesh
źródło
1

Rozszerzam rozwiązanie z jay_t55 o jeszcze jedną metodę, ToolStrip1_MouseLeavektóra obsługuje zdarzenie, w którym mysz porusza się szybko i opuszcza region.

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;
}
Michael
źródło
0

Wypróbowałem następujące i presto changeo, moje przezroczyste okno nie było już zamarznięte, ale można je było przesunąć !! (odrzuć wszystkie inne złożone rozwiązania powyżej ...)

   private void Window_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
        base.OnMouseLeftButtonDown(e);
        // Begin dragging the window
        this.DragMove();
    }
RoySeberg
źródło
Ta odpowiedź dotyczy WPF, pytanie dotyczy WinForms.
Ray
0

Formularz 1(): new Moveable(control1, control2, control3);

Klasa:

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; }
                }
            };
        }
    }
}
Soul Prodigy
źródło
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);
    }
Dragoslav Agbaba
źródło
Będzie miło, jeśli
wesprzesz