TMagnetic Pascal Unit für C++Builder 2009?



  • Hallo. Ich möchte gern wie bei Winamp realisieren das die Forms meiner Anwendung bei Näherung wie magnetisch angezogen werden und dann an der anderen Form kleben und sich mit bewegen.

    Ich habe dafür günstigerweise bei torry die Komponente TMagnetic Class (2009) gefunden. Diese besteht jedoch nur aus einer .pas Datei und .dcu. Wie erhalte ich daraus eine .hpp? Gibt es gar eine einfache C++Builder2009 Lösung? 🙂



  • .pas-Datei zum Projekt hinzufügen.



  • Oh so einfach. Danke schön! 🤡

    Ich habe es entsprechend dem Beispiel umgesetzt, scheitre aber scheinbar ein einer Funktion, da dort in der Funktion als Parameter eine Funktion aufgerufen wird.

    Pascal steht das

    // Code aus der Unit Magnet.pas
    TSubClass_Proc = function(lng_hWnd: HWND; uMsg: Integer; var Msg: TMessage; var bHandled: Boolean) : boolean;
    MagneticWndProc: TSubClass_Proc;
    
    TMagnetic = class
    public
    function  AddWindow(Handle: HWND; hWndParent: HWND; [b][u]var FuncPointer : TSubClass_Proc[/u][/b]): Boolean;
    end;
    // Ende
    
    // Beispielform verwendet das dann so
    procedure TfrmParent.FormShow(Sender: TObject);
    begin
      if Assigned(MagneticWnd) then
      begin
         // Register main window as a serviced window of TMagnetic Class
         MagneticWnd.AddWindow(Self.Handle, 0, MagneticWndProc);
      end;
    end;
    

    ich mache dies dann ebenfalls so:

    // In Magnet.hpp steht dann
    bool __fastcall AddWindow(HWND Handle, HWND hWndParent, TSubClass_Proc &FuncPointer);
    
    // In meiner Form steht das
    TSubClass_Proc MagneticWndProc;
    
    void __fastcall TForm1::FormShow(TObject *Sender)
    {
    	if (MagneticWnd)
    	{
    		MagneticWnd->AddWindow(Handle, 0, MagneticWndProc);
    	}
    }
    

    Er sagt mir dann allerdings

    [ILINK32 Fehler] Error: Nicht auflösbares externes '__fastcall Magnetic::TMagnetic::AddWindow(void *, void , bool __fastcall ()(void *, int, Messages::TMessage&, bool&)&)' referenziert von UNIT1.OBJ

    Kann mir jemand helfen wie man das realisieren kann?



  • Wenn es eine Komponente, wäre es doch ratsamer, diese erstmal zu installieren:
    - Neues Package erstellen.
    - Zu diesen die pas Datei hinzufügen.
    - In den Optionen muss noch eingestellt werden, das auch die C++ Dateien erzeugt werden sollen. Weiss aber aus dem Kopf nicht, wo genau das ist , aber diese Einstellung gibt es (selbst schon benutzt, ev. beim Linker).
    - Package installieren.



  • Es ist keine visuelle Komponente. Es ist eine Klasse die man einbindet und dann damit arbeitet. In der Komponente und im beiliegenden Beispiel wird gezeigt wie man dann seine TForm aufbereiten muss, damit es funktioniert.

    Es wird kein Code wie so etwas verwendet:

    initialization
      RegisterClasses([TComponentenName]);
    finalization
    end.
    

    Frage besteht damit weiterhin. Wie übergebe ich der Funktion AddWindow() als Parameter die Funktion MagneticWndProc(). 🙂



  • TM schrieb:

    Kann mir jemand helfen wie man das realisieren kann?

    Das ist ein Mangling-Problem. Ersetze in den Projektoptionen das Makro NO_STRICT durch STRICT.



  • Oh, ja das scheint zu helfen, vielen Dank!

    Ich komme mit dieser Funktion aber nicht ganz klar

    var
       MagneticWndProc : TSubClass_Proc;
    
    // procedure to subclass form's window procedure for magnetic effect.
    procedure TfrmChild3.WndProc(var Msg_ : TMessage);
    var
       Handled: boolean;
    begin
       if not Assigned(MagneticWndProc) then
       begin
          inherited WndProc(Msg_);
          exit;
       end;
    
       if (Msg_.Msg = WM_SYSCOMMAND) or (Msg_.Msg = WM_ENTERSIZEMOVE) or (Msg_.Msg = WM_EXITSIZEMOVE) or
           (Msg_.Msg = WM_WINDOWPOSCHANGED) or (Msg_.Msg = WM_COMMAND)then
       begin
          inherited WndProc(Msg_);
          MagneticWndProc(Self.Handle, Msg_.Msg, Msg_, Handled);
       end else if (Msg_.Msg = WM_MOVING) or (Msg_.Msg = WM_SIZING) then
       begin
          MagneticWndProc(Self.Handle, Msg_.Msg, Msg_, Handled);
          if not Handled then
             inherited WndProc(Msg_);
    
       end else
          inherited WndProc(Msg_);
    end;
    

    Da C++Builder2009 zu "MagneticWndProc : TSubClass_Proc;" doppelten Bezeichner meint, da dieser auch global in TForm1 vorhanden ist, habe ich dies in TForm2 zu "MagneticWndProc Sub" umbenannt.

    So habe ich das dann realisiert

    void __fastcall TForm2::WndProc(Messages::TMessage &Message)
    {
    	bool Handled;
    	if (!MagneticWndProcSub)
    	{
    		TForm::WndProc(Message);
    		return;
    	}
    
    	if ((Message.Msg == WM_SYSCOMMAND) ||
    		(Message.Msg == WM_ENTERSIZEMOVE) ||
    		(Message.Msg == WM_EXITSIZEMOVE) ||
    		(Message.Msg == WM_WINDOWPOSCHANGED) ||
    		(Message.Msg == WM_COMMAND))
    	{
    		TForm::WndProc(Message);
    		MagneticWndProcSub(Handle, Message.Msg, Message, Handled);
    		return;
    	}
    	else if ((Message.Msg == WM_MOVING) || (Message.Msg = WM_SIZING))
    	{
    		MagneticWndProcSub(Handle, Message.Msg, Message, Handled);
    		if (!Handled)
    		{
    			TForm::WndProc(Message);
    			return;
    		}
    	}
    
    	TForm::WndProc(Message);
    }
    

    Wenn ich die TForm2 aber aufrufe, dann erhalte ich ein "Zugriffsverletzung bei Adresse 500451D in Modul 'rtl120.bpl'. LEsen von Adresse 00000008."

    Kann mir jemand vielleicht gar meinen Fehler sagen?



  • Erledigt, habe die Funktion nochmal neu geschrieben und nun klappt alles 🙂


Anmelden zum Antworten