9

問題なくカスタム ドラッグ イメージを実装しました。

TDragControlObjectからクラスを継承し、そのGetDragImages関数をオーバーライドしてビットマップをTDragImageListに追加し、白いピクセルを透明にします。

動作します。白いピクセルは非表示 (透明) ですが、残りのビットマップは不透明ではありません。

このドラッグオブジェクトの動作を変更する方法はありますか?

ここに画像の説明を入力

4

1 に答える 1

10

使用できますImageList_SetDragCursorImage。これは通常、ドラッグ イメージとカーソル イメージのマージ イメージを提供するために使用されます。通常は、混乱を防ぐために実際のカーソルを非表示にします (2 つのカーソルを表示します)。

システムは、ドラッグ イメージの場合のように、カーソル イメージを背景とブレンドしません。したがって、カーソル イメージと同じドラッグ イメージを同じオフセットで提供し、実際のカーソルを非表示にしない場合、カーソル付きの不透明なドラッグ イメージになってしまいます。(同様に、空のドラッグ イメージを使用することもできますが、以前のデザインの方が実装しやすいと思います。)

以下のサンプル コード (XE2) は、W7x64 および XP の VM でテストされています。

unit Unit1;

interface

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

type
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    procedure Button2MouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure Button2StartDrag(Sender: TObject; var DragObject: TDragObject);
    procedure Button2EndDrag(Sender, Target: TObject; X, Y: Integer);
  private
    FDragObject: TDragObject;
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

uses
  commctrl;

{$R *.dfm}

type
  TMyDragObject = class(TDragObjectEx)
  private
    FDragImages: TDragImageList;
    FImageControl: TWinControl;
  protected
    function GetDragImages: TDragImageList; override;
  public
    constructor Create(ImageControl: TWinControl);
    destructor Destroy; override;
  end;

constructor TMyDragObject.Create(ImageControl: TWinControl);
begin
  inherited Create;
  FImageControl := ImageControl;
end;

destructor TMyDragObject.Destroy;
begin
  FDragImages.Free;
  inherited;
end;

function TMyDragObject.GetDragImages: TDragImageList;
var
  Bmp: TBitmap;
  Pt: TPoint;
begin
  if not Assigned(FDragImages) then begin
    Bmp := TBitmap.Create;
    try
      Bmp.PixelFormat := pf32bit;
      Bmp.Canvas.Brush.Color := clFuchsia;

      // 2px margin at each side just to show image can have transparency.
      Bmp.Width := FImageControl.Width + 4;
      Bmp.Height := FImageControl.Height + 4;
      Bmp.Canvas.Lock;
      FImageControl.PaintTo(Bmp.Canvas.Handle, 2, 2);
      Bmp.Canvas.Unlock;

      FDragImages := TDragImageList.Create(nil);
      FDragImages.Width := Bmp.Width;
      FDragImages.Height := Bmp.Height;
      Pt := Mouse.CursorPos;
      MapWindowPoints(HWND_DESKTOP, FImageControl.Handle, Pt, 1);
      FDragImages.DragHotspot := Pt;
      FDragImages.Masked := True;
      FDragImages.AddMasked(Bmp, clFuchsia);
    finally
      Bmp.Free;
    end;
  end;
  Result := FDragImages;
end;

//--

procedure TForm1.Button2MouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  (Sender as TWinControl).BeginDrag(False);

  // OnStartDrag is called during the above call so FDragImages is
  // assigned now.
  // The below is the only difference with a normal drag image implementation.
  ImageList_SetDragCursorImage(
      (FDragObject as TMyDragObject).GetDragImages.Handle, 0, 0, 0);
end;

procedure TForm1.Button2StartDrag(Sender: TObject; var DragObject: TDragObject);
begin
  DragObject := TMyDragObject.Create(Sender as TWinControl);
  DragObject.AlwaysShowDragImages := True;
  FDragObject := DragObject;
end;

end.


上記のコードのスクリーン ショット:

ここに画像の説明を入力

(実際のカーソルは crNoDrop でしたが、キャプチャ ソフトウェアはデフォルトのものを使用したことに注意してください。)

システムが画像に対して実際に何をするかを確認したい場合は、上記のImageList_SetDragCursorImage呼び出しを変更してホット スポットを作成します。

ImageList_SetDragCursorImage(
    (FDragObject as TMyDragObject).GetDragImages.Handle, 0, 15, 15);
// ShowCursor(False); // optional

これで、半透明の画像と不透明な画像の両方を同時に見ることができます。

于 2012-12-15T15:52:06.467 に答える