Magnetisches "ansnappen" von Forms



  • Aufgrund dessen, dass hier im Forum so viele Fragen zum "Snapping" aufgetaucht sind habe ich mich mal selber etwas mit dem Thema beschäftigt.

    Im folgenden Beispiel werden 2 Forms verwendet, wobei Form 2 diejenige ist die magnetisch an Form1 ansnappt:

    *.h

    //---------------------------------------------------------------------------
    
    #ifndef Unit2H
    #define Unit2H
    //---------------------------------------------------------------------------
    #include <Classes.hpp>
    #include <Controls.hpp>
    #include <StdCtrls.hpp>
    #include <Forms.hpp>
    
    #define NICHTGEDOCKT 0
    #define UNTEN        1
    #define OBEN         2
    #define RECHTS       3
    #define LINKS        4
    
    //---------------------------------------------------------------------------
    class TForm2 : public TForm
    {
    __published:    // Von der IDE verwaltete Komponenten
            void __fastcall FormMouseMove(TObject *Sender, TShiftState Shift, int X, int Y);
            void __fastcall FormMouseDown(TObject *Sender, TMouseButton Button,
              TShiftState Shift, int X, int Y);
    private:    // Anwender-Deklarationen
            int LastX, LastY; //letzte Mausposition
            HWND hwnd_Form1;  //Handle auf Form1
            TRect Form1Rect;  //Form1-Größeneigenschaften
            int MagneticDist; //magnetischer Abstand
            int Docked; //Zustandsvariable für Dock-Art
    public:     // Anwender-Deklarationen
            __fastcall TForm2(TComponent* Owner);
    };
    //---------------------------------------------------------------------------
    extern PACKAGE TForm2 *Form2;
    //---------------------------------------------------------------------------
    #endif
    

    *.cpp

    #include <vcl.h>
    #pragma hdrstop
    #include "Unit2.h"
    #include "Unit1.h"
    //---------------------------------------------------------------------------
    #pragma package(smart_init)
    #pragma resource "*.dfm"
    TForm2 *Form2;
    //---------------------------------------------------------------------------
    __fastcall TForm2::TForm2(TComponent* Owner) : TForm(Owner)
    {
            MagneticDist = 50;
            Docked = NICHTGEDOCKT;
    }
    //---------------------------------------------------------------------------
    
    void __fastcall TForm2::FormMouseMove(TObject *Sender, TShiftState Shift, int X, int Y)
    {
            TPoint P;
    
            if (Shift.Contains(ssLeft))
            {
                    P = Mouse->CursorPos;
                    // Verschiebemöglichkeiten entsprechend des Dockstatus
                    switch (Docked)
                    {
                            case OBEN:         Form2->Left = P.x - LastX;
                                               break;
                            case UNTEN:        Form2->Left = P.x - LastX;
                                               break;
                            case LINKS:        Form2->Top = P.y - LastY;;
                                               break;
                            case RECHTS:       Form2->Top = P.y - LastY;
                                               break;
                            case NICHTGEDOCKT: Form2->Top = P.y - LastY;
                                               Form2->Left = P.x - LastX;
                                               break;
                    }
    
                    if (hwnd_Form1)
                    {
                            // von oben
                            if (abs(Form1Rect.Top - (Form2->Top + Form2->Height)) < MagneticDist)
                            {
                                    if (((Form2->Left + Form2->Width) >= Form1Rect.Left) && (Form2->Left <= Form1Rect.Right))
                                    {
                                            Form2->Top = Form1Rect.Top-Form2->Height;
                                            P.x = Form2->Left + LastX;
                                            P.y = Form2->Top + LastY;
    
                                            Mouse->CursorPos = P;
                                            Docked = OBEN;
                                            return;
                                    }
                            }
    
                            // von unten
                            if (abs(Form1Rect.Bottom - Form2->Top) < MagneticDist)
                            {
                                    if (((Form2->Left + Form2->Width) >= Form1Rect.Left) && (Form2->Left <= Form1Rect.Right))
                                    {
                                            Form2->Top = Form1Rect.Bottom;
                                            P.x = Form2->Left + LastX;
                                            P.y = Form2->Top + LastY;
    
                                            Mouse->CursorPos = P;
                                            Docked = UNTEN;
                                            return;
                                    }
                            }
    
                            // von links
                            if (abs(Form1Rect.Left - (Form2->Left + Form2->Width)) < MagneticDist)
                            {
                                    if (((Form2->Top + Form2->Height) >= Form1Rect.Top) && (Form2->Top <= Form1Rect.Bottom))
                                    {
                                            Form2->Left = Form1Rect.Left-Form2->Width;
                                            P.x = Form2->Left + LastX;
                                            P.y = Form2->Top + LastY;
    
                                            Mouse->CursorPos = P;
                                            Docked = LINKS;
                                            return;
                                    }
                            }
    
                            // von rechts
                            if (abs(Form1Rect.Right - Form2->Left) < MagneticDist)
                            {
                                    if (((Form2->Top + Form2->Height) >= Form1Rect.Top) && (Form2->Top <= Form1Rect.Bottom))
                                    {
                                            Form2->Left = Form1Rect.Right;
                                            P.x = Form2->Left + LastX;
                                            P.y = Form2->Top + LastY;
    
                                            Mouse->CursorPos = P;
                                            Docked = RECHTS;
                                            return;
                                    }
                            }
    
                            // Ansonsten ist nichts passiert
                            Docked = NICHTGEDOCKT;
                    }
            }
    }
    //---------------------------------------------------------------------------
    
    void __fastcall TForm2::FormMouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
    {
            // Variablen initialisieren
            LastX = X;
            LastY = Y;
            hwnd_Form1 = FindWindow("TForm1", NULL); //Form1 suchen
            if (hwnd_Form1) GetWindowRect(hwnd_Form1, &Form1Rect); //Fensterkoordinaten bestimmen
    }
    

    Das Problem hierbei ist noch, das man wenn Form2 an Form1 angesnappt ist es nur noch schwer über Eck wieder losbekommt. Wenn jemand eine Lösung dazu weis ...

    [ Dieser Beitrag wurde am 19.02.2003 um 16:37 Uhr von F98 editiert. ]



  • Eine Lösung, die mir jetzt noch schnell eingefallen ist, ist die MagneticDist nach dem Andocken auf 0 zu setzen.


Anmelden zum Antworten