⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 main.pas

📁 Drag files and Drop to delphi forms 0402
💻 PAS
字号:
unit main;

interface

uses
  DragDrop, DropSource, DragDropFormats,
  Messages,
  ActiveX, Windows, Classes, Controls, Forms, StdCtrls, ComCtrls, ExtCtrls,
  Buttons;

const
  MSG_PROGRESS = WM_USER;
  MSG_STATUS = WM_USER+1;

type
  TDragDropStage = (dsNone, dsIdle, dsDrag, dsDragAsync, dsDragAsyncFailed, dsDrop, dsGetData, dsGetStream, dsDropComplete);

type
  TFormMain = class(TForm)
    Timer1: TTimer;
    Panel2: TPanel;
    DropEmptySource1: TDropEmptySource;
    DataFormatAdapterSource: TDataFormatAdapter;
    ProgressBar1: TProgressBar;
    Panel3: TPanel;
    Panel4: TPanel;
    Panel5: TPanel;
    RadioButtonNormal: TRadioButton;
    RadioButtonAsync: TRadioButton;
    PaintBoxPie: TPaintBox;
    Label1: TLabel;
    Label2: TLabel;
    Label3: TLabel;
    Label4: TLabel;
    StatusBar1: TStatusBar;
    ButtonAbort: TSpeedButton;
    procedure Timer1Timer(Sender: TObject);
    procedure DropEmptySource1Drop(Sender: TObject; DragType: TDragType;
      var ContinueDrop: Boolean);
    procedure DropEmptySource1AfterDrop(Sender: TObject;
      DragResult: TDragResult; Optimized: Boolean);
    procedure DropEmptySource1GetData(Sender: TObject;
      const FormatEtc: tagFORMATETC; out Medium: tagSTGMEDIUM;
      var Handled: Boolean);
    procedure OnMouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure FormCreate(Sender: TObject);
    procedure ButtonAbortClick(Sender: TObject);
    procedure StatusBar1Resize(Sender: TObject);
  private
    FStatus: TDragDropStage;
    FAbort: boolean;
    Tick: integer;
    EvenOdd: boolean;
    procedure SetStatus(const Value: TDragDropStage);
    procedure SetProgress(Count, MaxCount: integer);
    procedure OnGetStream(Sender: TFileContentsStreamOnDemandClipboardFormat;
      Index: integer; out AStream: IStream);
    procedure OnProgress(Sender: TObject; Count, MaxCount: integer);
    procedure MsgProgress(var Message: TMessage); message MSG_PROGRESS;
    procedure MsgStatus(var Message: TMessage); message MSG_STATUS;
    property Status: TDragDropStage read FStatus write SetStatus;
  public
  end;

var
  FormMain: TFormMain;

implementation

{$R *.DFM}

uses
  ShlObj,
  Graphics;

const
  TestFileSize = 1024*1024*100; // 100Mb

procedure TFormMain.FormCreate(Sender: TObject);
begin
  // Setup event handler to let a drop target request data from our drop source.
  (DataFormatAdapterSource.DataFormat as TVirtualFileStreamDataFormat).OnGetStream := OnGetStream;

  StatusBar1.ControlStyle := StatusBar1.ControlStyle +[csAcceptsControls];
  Status := dsIdle;
(*
  // Reparent abort button to statusbar
  ButtonAbort.Top := 3;
  ButtonAbort.Height := StatusBar1.Height-4;
  ButtonAbort.Left := StatusBar1.Width-ButtonAbort.Width-1;
*)
end;

procedure TFormMain.Timer1Timer(Sender: TObject);

  procedure DrawPie(Percent: integer);
  var
    Center: TPoint;
    Radial: TPoint;
    v: Double;
    Radius: integer;
  begin
    // Assume paintbox width is smaller than height.
    Radius := PaintBoxPie.Width div 2 - 10;
    Center := Point(PaintBoxPie.Width div 2, PaintBoxPie.Height div 2);
    v := Percent * Pi / 50; // Convert percent to radians.
    Radial.X := Center.X+trunc(Radius * Cos(v));
    Radial.Y := Center.Y-trunc(Radius * Sin(v));

    PaintBoxPie.Canvas.Brush.Style := bsSolid;
    PaintBoxPie.Canvas.Pen.Color := clGray;
    PaintBoxPie.Canvas.Pen.Style := psSolid;

    if (EvenOdd) then
      PaintBoxPie.Canvas.Brush.Color := clRed
    else
      PaintBoxPie.Canvas.Brush.Color := Color;
    PaintBoxPie.Canvas.Pie(Center.X-Radius, Center.Y-Radius,
      Center.X+Radius, Center.Y+Radius,
      Radial.X, Radial.Y,
      Center.X+Radius, Center.Y);

    if (Percent <> 0) then
    begin
      if not(EvenOdd) then
        PaintBoxPie.Canvas.Brush.Color := clRed
      else
        PaintBoxPie.Canvas.Brush.Color := Color;
      PaintBoxPie.Canvas.Pie(Center.X-Radius, Center.Y-Radius,
        Center.X+Radius, Center.Y+Radius,
        Center.X+Radius, Center.Y,
        Radial.X, Radial.Y);
    end;
  end;

begin
  // Update the pie to indicate that the application is responding to
  // messages (i.e. isn't blocked).
  Tick := (Tick + 10) mod 100;
  if (Tick = 0) then
    EvenOdd := not EvenOdd;

  // Draw an animated pie chart to show that application is responsive to events.
  DrawPie(Tick);
end;

procedure TFormMain.OnMouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  Status := dsIdle;
  if DragDetectPlus(Handle, Point(X, Y)) then
  begin
    Status := dsDrag;

    // Transfer the file names to the data format.
    // The content will be extracted by the target on-demand.
    TVirtualFileStreamDataFormat(DataFormatAdapterSource.DataFormat).FileNames.Clear;
    TVirtualFileStreamDataFormat(DataFormatAdapterSource.DataFormat).FileNames.Add('big text file.txt');
    // Set the size and timestamp attributes of the filename we just added.
    with PFileDescriptor(TVirtualFileStreamDataFormat(DataFormatAdapterSource.DataFormat).FileDescriptors[0])^ do
    begin
      GetSystemTimeAsFileTime(ftLastWriteTime);
      nFileSizeLow := TestFileSize and $00000000FFFFFFFF;
      nFileSizeHigh := (TestFileSize and $FFFFFFFF00000000) shr 32;
      dwFlags := FD_WRITESTIME or FD_FILESIZE or FD_PROGRESSUI;
    end;

    // Determine if we should perform an async drag or a normal drag.
    if (RadioButtonAsync.Checked) then
    begin
      FAbort := False;

      // Perform an asynchronous drag (in a separate thread).
      if (DropEmptySource1.Execute(True) = drAsync) then
        Status := dsDragAsync
      else
        Status := dsDragAsyncFailed;
    end else
    begin
      // Perform a normal drag (in the main thread).
      DropEmptySource1.Execute;

      Status := dsIdle;
    end;
  end;
end;

procedure TFormMain.DropEmptySource1Drop(Sender: TObject;
  DragType: TDragType; var ContinueDrop: Boolean);
begin
  // Warning:
  // This event will be called in the context of the transfer thread during an
  // asynchronous transfer. See TFormMain.OnProgress for a comment on this.
  Status := dsDrop;
end;

procedure TFormMain.DropEmptySource1AfterDrop(Sender: TObject;
  DragResult: TDragResult; Optimized: Boolean);
begin
  Status := dsDropComplete;
end;

procedure TFormMain.DropEmptySource1GetData(Sender: TObject;
  const FormatEtc: tagFORMATETC; out Medium: tagSTGMEDIUM;
  var Handled: Boolean);
begin
  // Warning:
  // This event will be called in the context of the transfer thread during an
  // asynchronous transfer. See TFormMain.OnProgress for a comment on this.
  Status := dsGetData;
end;

type
  TStreamProgressEvent = procedure(Sender: TObject; Count, MaxCount: integer) of object;

  // TFakeStream is a read-only stream which produces its contents on-the-run.
  // It is used for this demo so we can simulate transfer of very large and
  // arbitrary amounts of data without using any memory.
  TFakeStream = class(TStream)
  private
    FSize, FPosition, FMaxCount: Longint;
    FProgress: TStreamProgressEvent;
    FAbort: boolean;
  protected
  public
    constructor Create(ASize, AMaxCount: LongInt);
    function Read(var Buffer; Count: Longint): Longint; override;
    function Seek(Offset: Longint; Origin: Word): Longint; override;
    procedure SetSize(NewSize: Longint); override;
    function Write(const Buffer; Count: Longint): Longint; override;
    procedure Abort;
    property OnProgress: TStreamProgressEvent read FProgress write FProgress;
  end;

procedure TFakeStream.Abort;
begin
  FAbort := True;
end;

constructor TFakeStream.Create(ASize, AMaxCount: LongInt);
begin
  inherited Create;
  FSize := ASize;
  FMaxCount := AMaxCount;
end;

function TFakeStream.Read(var Buffer; Count: Integer): Longint;
begin
  Result := 0;
  if (FAbort) then
    exit;

  if (FPosition >= 0) and (Count >= 0) then
  begin
    Result := FSize - FPosition;
    if Result > 0 then
    begin
      if Result > Count then
        Result := Count;
      if Result > FMaxCount then
        Result := FMaxCount;
      FillChar(Buffer, Result, ord('X'));
      Inc(FPosition, Result);
      if Assigned(FProgress) then
        FProgress(Self, FPosition, FSize);
    end;
  end;
end;

function TFakeStream.Seek(Offset: Integer; Origin: Word): Longint;
begin
  case Origin of
    soFromBeginning: FPosition := Offset;
    soFromCurrent: Inc(FPosition, Offset);
    soFromEnd: FPosition := FSize + Offset;
  end;
  if Assigned(FProgress) then
    FProgress(Self, FPosition, FMaxCount);
  Result := FPosition;
end;

procedure TFakeStream.SetSize(NewSize: Integer);
begin
end;

function TFakeStream.Write(const Buffer; Count: Integer): Longint;
begin
  Result := 0;
end;

procedure TFormMain.OnGetStream(Sender: TFileContentsStreamOnDemandClipboardFormat;
  Index: integer; out AStream: IStream);
var
  Stream: TStream;
begin
  // Warning:
  // This method will be called in the context of the transfer thread during an
  // asynchronous transfer. See TFormMain.OnProgress for a comment on this.

  // This event handler is called by TFileContentsStreamOnDemandClipboardFormat
  // when the drop target requests data from the drop source (that's us).
  Status := dsGetStream;

  // In this demo we just create a dummy stream which contains 10Mb of 'X'
  // characters. In order to provide smoth feedback through the progress bar
  // (and slow the transfer down a bit) the stream will only transfer up to 32K
  // at a time - Each time TStream.Read is called, the progress bar is updated
  // via the stream's progress event.

  // Create a stream which contains the data to transfer...
  Stream := TFakeStream.Create(TestFileSize, 32*1024);
  try
    TFakeStream(Stream).OnProgress := OnProgress;
    // ...and return the stream back to the target as an IStream. Note that the
    // target is responsible for deleting the stream (via reference counting).
    AStream := TFixedStreamAdapter.Create(Stream, soOwned);
  except
    Stream.Free;
    raise;
  end;

  // Initialize progress bar
  SetProgress(0, 0);
end;

procedure TFormMain.OnProgress(Sender: TObject; Count, MaxCount: integer);
begin
  // Note that during an asynchronous transfer, some event handlers are
  // being called in the context of the transfer thread. This means that these
  // event handlers should adhere to all the normal thread safety rules (i.e.
  // don't call GDI or mess with non-thread safe objects).

  // Update progress bar to show how much data has been transfered so far.
  SetProgress(Count, MaxCount);
  if (FAbort) then
    TFakeStream(Sender).Abort;
end;

procedure TFormMain.ButtonAbortClick(Sender: TObject);
begin
  FAbort := True;
  TButton(Sender).Enabled := False;
end;

procedure TFormMain.StatusBar1Resize(Sender: TObject);
begin
  // This is nescessary to get controls inside TStatusBar to honour Anchors.
  StatusBar1.Realign;
end;

procedure TFormMain.MsgProgress(var Message: TMessage);
begin
  SetProgress(Message.WParam, Message.LParam);
end;

procedure TFormMain.SetProgress(Count, MaxCount: integer);
begin
  // Make sure GUI updates are performed in the main thread.
  if (GetCurrentThreadID <> MainThreadID) then
  begin
    PostMessage(Handle, MSG_PROGRESS, Count, MaxCount);
    exit;
  end;

  ProgressBar1.Max := MaxCount;
  ProgressBar1.Position := Count;
end;

procedure TFormMain.MsgStatus(var Message: TMessage);
begin
  SetStatus(TDragDropStage(Message.WParam));
end;

procedure TFormMain.SetStatus(const Value: TDragDropStage);
begin
  // Make sure GUI updates are performed in the main thread.
  if (GetCurrentThreadID <> MainThreadID) then
  begin
    PostMessage(Handle, MSG_STATUS, ord(Value), 0);
    exit;
  end;

  if (FStatus <> Value) then
  begin
    FStatus := Value;
    case FStatus of
      dsIdle:
        StatusBar1.SimpleText := 'Ready';
      dsDrag:
        StatusBar1.SimpleText := 'Drag in progress';
      dsDragAsync:
        StatusBar1.SimpleText := 'Asynchronous drag started';
      dsDragAsyncFailed:
        StatusBar1.SimpleText := 'Asynchronous drag failed';
      dsDrop:
        begin
          StatusBar1.SimpleText := 'Data dropped';
          if (RadioButtonAsync.Checked) then
          begin
            ButtonAbort.Visible := True;
            ButtonAbort.Enabled := True;
          end;
        end;
      dsGetData:
        StatusBar1.SimpleText := 'Target reading data';
      dsGetStream:
        StatusBar1.SimpleText := 'Source writing data';
      dsDropComplete:
        begin
          StatusBar1.SimpleText := 'Drop completed';
          ButtonAbort.Visible := False;
        end;
    else
      StatusBar1.SimpleText := '';
    end;
  end;
end;

end.

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -