2012-10-18 9 views
6

Ich versuche, die Tab-Drag-Funktionalität von Chrome zu emulieren. Ich möchte, dass der Benutzer eine Registerkarte an eine neue Position in der Registerkarte ziehen oder außerhalb der Anwendung ablegen kann, um ein neues Fenster zu erstellen. Ziehen innerhalb der Anwendung ist einfach, aber wie erkenne ich, wenn ein Benutzer irgendwo nicht in meiner App ablegt?Wie erkenne ich einen Drag-Drop außerhalb Ihrer Anwendung?

Im Wesentlichen möchte ich "abreißen" Tabs implementieren.

+0

Link von irgendeiner Hilfe ist, [Drag/Drop-innerhalb einer Anwendung und auf eine andere Anwendung] (http://stackoverflow.com/q/198488/576719)? –

+1

@LURD: Ich dachte es auch und nannte es fast ein Duplikat, bis ich die Frage erneut las und das "um ein neues Fenster zu erstellen" sah. Das ist nicht "eine andere Anwendung"; Es erstellt ein neues Fenster in Ihrer eigenen Anwendung, wenn etwas außerhalb davon abgelegt wird. Ich habe stattdessen hochgestuft. :-) Es scheint eine gute Frage zu sein. –

+0

@KenWhite, Sie haben Recht. Probieren Sie diese Funktion in Chrome aus. –

Antwort

7

Da die Maus während einer Ziehoperation erfasst wird, gibt es kein Problem mit der Erkennung, wenn eine Ziehoperation in einem OnEndDrag-Handler abgeschlossen ist, auch wenn sie sich außerhalb der Form der Anwendung befindet. Sie können feststellen, ob der Drop akzeptiert wird oder nicht, indem Sie das Zielobjekt testen, und wenn der Drop nicht akzeptiert wird, können Sie feststellen, ob es sich außerhalb der Anwendung befindet, indem Sie die Mausposition testen.

Allerdings gibt es immer noch ein Problem mit diesem Ansatz. Sie können nicht feststellen, ob der Ziehvorgang abgebrochen wurde, indem Sie die Taste 'Esc' drücken. Es gibt auch das Problem, den Drag-Cursor außerhalb des Formulars nicht auf 'akzeptiert' setzen zu können, da dort kein Steuerelement OnDragOver aufgerufen wird.

Sie können dieses Problem beheben, indem Sie das Verhalten der Ziehoperation mithilfe eines Ziehobjekts Ihrer Erstellung ändern. Im Folgenden finden Sie ein Beispiel:

unit Unit1; 

interface 

uses 
    Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, 
    Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.ComCtrls; 

type 
    TForm1 = class(TForm) 
    PageControl1: TPageControl; 
    TabSheet1: TTabSheet; 
    TabSheet2: TTabSheet; 
    TabSheet3: TTabSheet; 
    procedure FormCreate(Sender: TObject); 
    procedure PageControl1MouseDown(Sender: TObject; Button: TMouseButton; 
     Shift: TShiftState; X, Y: Integer); 
    procedure PageControl1StartDrag(Sender: TObject; 
     var DragObject: TDragObject); 
    procedure PageControl1EndDrag(Sender, Target: TObject; X, Y: Integer); 
    procedure PageControl1DragOver(Sender, Source: TObject; X, Y: Integer; 
     State: TDragState; var Accept: Boolean); 
    end; 

var 
    Form1: TForm1; 

implementation 

{$R *.dfm} 

procedure TForm1.FormCreate(Sender: TObject); 
begin 
    PageControl1.DragMode := dmManual; 
end; 


type 
    TDragFloatSheet = class(TDragControlObjectEx) 
    private 
    class var 
     FDragSheet: TTabSheet; 
     FDragPos: TPoint; 
     FCancelled: Boolean; 
    protected 
    procedure WndProc(var Msg: TMessage); override; 
    end; 

procedure TDragFloatSheet.WndProc(var Msg: TMessage); 
begin 
    if (Msg.Msg = CN_KEYDOWN) and (Msg.WParam = VK_ESCAPE) then 
    FCancelled := True; 
    FDragPos := DragPos; 
    inherited; 
    if (Msg.Msg = WM_MOUSEMOVE) and 
     (not Assigned(FindVCLWindow(SmallPointToPoint(TWMMouse(Msg).Pos)))) then 
    Winapi.Windows.SetCursor(Screen.Cursors[GetDragCursor(True, 0, 0)]); 
end; 

//------------------- 

procedure TForm1.PageControl1MouseDown(Sender: TObject; Button: TMouseButton; 
    Shift: TShiftState; X, Y: Integer); 
begin 
    TDragFloatSheet.FDragSheet := 
     (Sender as TPageControl).Pages[TPageControl(Sender).IndexOfTabAt(X, Y)]; 
    PageControl1.BeginDrag(False); 
end; 

procedure TForm1.PageControl1StartDrag(Sender: TObject; 
    var DragObject: TDragObject); 
begin 
    DragObject := TDragFloatSheet.Create(Sender as TPageControl); 
end; 

procedure TForm1.PageControl1DragOver(Sender, Source: TObject; X, Y: Integer; 
    State: TDragState; var Accept: Boolean); 
var 
    TargetSheet: TTabSheet; 
begin 
    TargetSheet := 
     (Sender as TPageControl).Pages[TPageControl(Sender).IndexOfTabAt(X, Y)]; 
    Accept := Assigned(TargetSheet) and (TargetSheet <> TDragFloatSheet.FDragSheet); 
end; 

procedure TForm1.PageControl1EndDrag(Sender, Target: TObject; X, Y: Integer); 
begin 
    if Assigned(Target) then begin 

    // normal processing, f.i. find the target tab as in OnDragOver 
    // and switch positions with TDragFloatSheet.FDragSheet 

    end else begin 
    if not TDragFloatSheet.FCancelled then begin 
     if not Assigned(FindVCLWindow(TDragFloatSheet.FDragPos)) then begin 

     // drop TDragFloatSheet.FDragSheet at TDragFloatSheet.FDragPos 

     end; 
    end; 
    end; 
end; 

end. 
+1

+1. Sehr schön gemacht! :-) –

+0

Große Antwort Sertac. Vielen Dank. – norgepaul

Verwandte Themen