問題なくカスタム ドラッグ イメージを実装しました。
TDragControlObjectからクラスを継承し、そのGetDragImages関数をオーバーライドしてビットマップをTDragImageListに追加し、白いピクセルを透明にします。
動作します。白いピクセルは非表示 (透明) ですが、残りのビットマップは不透明ではありません。
このドラッグオブジェクトの動作を変更する方法はありますか?
問題なくカスタム ドラッグ イメージを実装しました。
TDragControlObjectからクラスを継承し、そのGetDragImages関数をオーバーライドしてビットマップをTDragImageListに追加し、白いピクセルを透明にします。
動作します。白いピクセルは非表示 (透明) ですが、残りのビットマップは不透明ではありません。
このドラッグオブジェクトの動作を変更する方法はありますか?
使用できます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
これで、半透明の画像と不透明な画像の両方を同時に見ることができます。