How do you use TDragObject to show different images while dragging? lazarus / 39-Graphics ---------------------------------------------------------------------- EganSolo · 2022-03-02 09:07 I've read as much as I could find about TDragObject and I'm still unclear on how to specify the images to show while dragging. I've attached two images taken from Visio to illustrate what I would like to do: In the first image, I click on a rectangle in a stencil and drag: a small white rectangle is then displayed with the cursor. That rectangle in the attached image is framed in red. In the second image, the cursor has left the stencil and has reached the main drawing area: there, the image attached to the cursor is that of a larger rectangle, framed in red as well. I think I should be able to do that by specializing the TDragObject, which I suspect must carry two different images and show each of them depending on the current sender that is being traversed by the mouse. Below is the declaration of TDragObject taken from the Controls unit. Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i   TDragObject = class  private    FAlwaysShowDragImages: Boolean;    FDragPos: TPoint;    FControl: TControl;    FDragTarget: TControl;    FDragTargetPos: TPoint;    FAutoFree: Boolean;    FAutoCreated: Boolean;    FDropped: Boolean;  protected    procedure EndDrag(Target: TObject; X, Y: Integer); virtual;    function GetDragImages: TDragImageList; virtual;    function GetDragCursor(Accepted: Boolean; X, Y: Integer): TCursor; virtual;  public    constructor Create(AControl: TControl); virtual;    constructor AutoCreate(AControl: TControl);     procedure HideDragImage; virtual;    procedure ShowDragImage; virtual;     property AlwaysShowDragImages: Boolean read FAlwaysShowDragImages write FAlwaysShowDragImages;    property AutoCreated: Boolean read FAutoCreated;    property AutoFree: Boolean read FAutoFree;    property Control: TControl read FControl write FControl; // the dragged control    property DragPos: TPoint read FDragPos write FDragPos;    property DragTarget: TControl read FDragTarget write FDragTarget;    property DragTargetPos: TPoint read FDragTargetPos write FDragTargetPos;    property Dropped: Boolean read FDropped;  end;  I don't see any method to add an image. How do I specify the images I want to be shown while draggin? I think I'm getting something wrong here. Any hint would help. ---------------------------------------------------------------------- EganSolo · 2022-03-03 09:44 Alright, I've made some progress in my comprehension of Drag and Drop and I think I know how _conceptually_ my request should work, but something is wrong with the attached code. I have a form with three panels: top, left and right. The left and right panel accept drag and drop whereas the top panel does not. The top panel holds an image which is draggable (DragMode = dmAutomatic). The Idea: When dragging the image over the left panel, an identical image should be displayed alongside the cursor. When dragging it over the right panel, a larger version of that image should be displayed with the cursor. Current outcome: no image is showing. Idea behind the code: Create a descendant of TDragObject (included in the project)Override GetDragImages to return a list of images to display during the drag/drop operation. Let this method return a list of small images or a list of large images depending on whether the dragging is over the left or right panel.On the start of the drag operation in the eh_StartDrag, set the var DragObject to an instance of the descendant classWithin the DragOver event handler, Set a flag on the drag object to let it know which of the two lists to return. This is done when the variable DragState = dsEnter and DragState = dsLeave These steps, should, in principle instruct the drag object on the image to return, but like I said the code does not (yet) work. Here are some of the most important aspects of the code should you prefer not to load the project.  Below, is the declaration of TWidgetDragObject which is the descendant of the TDragObject. Note the declaration of fDragSmallImages and fDragLargeImages which are the two lists that will house the small and large images respectively. Also, the enumeration enum_UseImages is used to instruct GetDragImages on which of these two lists to return. StartDrag is used to set UseImages and the X and Y position. Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i   { TWidgetDragObject }  enum_UseImages = (ui_None, ui_Small, ui_Large);   TWidgetDragObject = class(TDragObject)  private     fDragSmallImages : TDragImageList     ;     fDragLargeImages   : TDragImageList     ;   fUseImages         : enum_UseImages     ;     fXpos              : integer            ;     fYpos              : integer            ;     procedure SetUseImages(const aValue: enum_UseImages);  protected     function  GetDragImages : TDragImageList; override;  public     Constructor Create(AControl: TControl); override;     Destructor Destroy; override;     procedure StartDrag(const aUseImages: enum_UseImages; const anXPos: integer; const aYPos: integer);     Procedure LoadSmallImagesFromList(Const anImageList : TImageList);   Procedure LoadLargeImagesFromList(const anImageList : TImageList);  public     Property UseImages     : enum_UseImages read fUseImages write SetUseImages;     Property Xpos          : integer read fXpos;   Property Ypos          : integer read fYpos;  end;  Here is the method GetDragImages. The call to SetDragImage tells the image list which image to return based on the index. Since we have one image only in each of the lists, the index is always 0. Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i function TWidgetDragObject.GetDragImages: TDragImageList;var Idx : integer;begin  If UseImages = ui_Small  then begin        Result := fDragSmallImages;        Idx := 0;        Result.SetDragImage(Idx,XPos,YPos);  end  else If UseImages = ui_Large  then begin      Result := fDragLargeImages;      Idx    := 0;      Result.SetDragImage(Idx,XPos,YPos);  end  else Result := Inherited;end;  Here is the declaration of the form. Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i    TForm1 = class(TForm)      pnl_Right: TPanel;      pnl_Left: TPanel;      pnl_Top: TPanel;      Image: TImage;      LargeImage: TImageList;    SmallImage: TImageList;      procedure eh_MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X , Y: Integer);      procedure eh_StartDrag(Sender: TObject; var DragObject: TDragObject);      procedure eh_DragOver(Sender , Source: TObject; X , Y: Integer; State: TDragState; var Accept: Boolean);      procedure FormCreate(Sender: TObject);      procedure FormDestroy(Sender: TObject);   private      fDragObject    : TWidgetDragObject;   end;  fDragObject is created in the FormCreate method and destroyed in the FormDestroy method. Here is the Start Drag event: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure TForm1.eh_StartDrag(Sender: TObject; var DragObject: TDragObject);var Pt     : TPoint;begin  Pt.X := 0; Pt.Y := 0;  GetCursorPos(Pt);  Pt := Image.ScreenToClient(Pt);  fDragObject.StartDrag(ui_None, Pt.X, pt.Y);  fDragObject.Control := Image;  DragObject := fDragObject;end;  Basically, it calls the StartDrag method on the drag object, sets its control to the Image which is the source control, and returns it via the DragObject variable. Here is the DragOver method. Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure TForm1.eh_DragOver(Sender , Source: TObject; X , Y: Integer; State: TDragState; var Accept: Boolean);var aPanel : TPanel;begin   accept := true;   aPanel := Sender as TPanel;   If State = dsDragEnter   then If aPanel.Caption = 'Left'        then fDragObject.UseImages:= ui_Small      else fDragObject.UseImages:= ui_Large   else If State = dsDragLeave        then fDragObject.UseImages := ui_None;end;  After telling the Drag/drop manager that the panels accept drag and drop, it determines which of the two lists should be used to return an image. If you peruse the project, you will see that the code is mostly straightforward, but I can't figure out why the images aren't showing. Any thoughts would be appreciated.