3

I'm trying to achieve a simple drag and drop-panel, where a user can drop a file from windows explorer. The basic functionality is already working after I found this Thread.

Now I'm trying to change the color of the panel, while the user is dragging a file over it. I tried to use OnDragOver, but nothing happens. What am I doing wrong?

This is my current code:

unit main;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ShellApi,
  Vcl.ExtCtrls, Vcl.Imaging.pngimage;

type
   TPanel = class(Vcl.ExtCtrls.TPanel)
     protected
       procedure WMDropFiles(var Message: TWMDropFiles); message WM_DROPFILES;
       procedure CreateWnd; override;
       procedure DestroyWnd; override;
     end;

  TfrmMain = class(TForm)
    panFileDrop: TPanel;
    lblFileName: TLabel;
    procedure panFileDropDragOver(Sender, Source: TObject; X, Y: Integer;
      State: TDragState; var Accept: Boolean);
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

var
  frmMain: TfrmMain;

implementation

{$R *.dfm}

procedure TPanel.CreateWnd;
begin
   inherited;
   DragAcceptFiles(Handle, true);
end;

procedure TPanel.DestroyWnd;
begin
   DragAcceptFiles(Handle, false);
   inherited;
end;

procedure TPanel.WMDropFiles(var Message: TWMDropFiles);
var
  c: integer;
  fn: array[0..MAX_PATH-1] of char;
begin

  c := DragQueryFile(Message.Drop, $FFFFFFFF, fn, MAX_PATH);

  if c <> 1 then
  begin
    MessageBox(Handle, 'Too many files.', 'Drag and drop error', MB_ICONERROR);
    Exit;
  end;

  if DragQueryFile(Message.Drop, 0, fn, MAX_PATH) = 0 then Exit;

  frmMain.lblFileName.Caption := fn;

end;

procedure TfrmMain.panFileDropDragOver(Sender, Source: TObject; X, Y: Integer;
  State: TDragState; var Accept: Boolean);
begin
   panFileDrop.Color := $00d4d3d2;
end;

end.
Community
  • 1
  • 1
Simon L.
  • 33
  • 1
  • 4
  • Have you debuged it to see the DragOver event is executed ? – GuidoG Sep 05 '16 at 11:23
  • Yes, I used a ShowMessage but it didn't show up. – Simon L. Sep 05 '16 at 11:25
  • showmessage is not a good debugger, set a breakpoint in the first line of your onDragOver event and check you get there, and if you do then debug every line of code in there. If you dont then something else is wrong in some code we cannot see – GuidoG Sep 05 '16 at 11:29
  • I'll try when I'm back in the office. But my approach is right? – Simon L. Sep 05 '16 at 11:34
  • I would not go as far as overriding CreateWnd and DestroyWnd a panel has a constructor you can override and there is no need to cancel the DragAcceptFiles in the destroy because the panel wont exist anymore after it anyway. The OnDragOver event would be also my first choice to try this – GuidoG Sep 05 '16 at 11:44
  • I just copied the code from the thread I linked in the question and it works, so I left it this way :). If I set a breakpoint in my OnDragOverEvent, nothing happens, so I guess the event isn't executed. – Simon L. Sep 05 '16 at 12:00
  • After some further testing it looks like the problem is that I drag a file from the "outside" of the application. OnDragOver works if I drag e.g. a button over the panel. But If I drag a file from windows explorer, the event isn't executed. Maybe there is a windows message where i could change the color of my panel? – Simon L. Sep 05 '16 at 12:25
  • Than I would change this question to "why does OnDragOver not works when dragging from external" or something like this, or close this question and create a new one. – GuidoG Sep 05 '16 at 12:38
  • Debugging as Guido suggests is also not very effective. Break points change behaviour of app doing debugged. Old school trace debugging needed. – David Heffernan Sep 05 '16 at 12:57
  • @DavidHeffernan I just wanted to find out if the OnDragOver ever got fired or not, for that a breakpoint can still be sufficient. But since the OP has stated that the event is fired when dragging an internal control, but not fired when dragging something external (like a file from explorer) I guess there will not be much to debug here at all ? – GuidoG Sep 05 '16 at 13:50
  • 1
    `OnDragOver` is a VCL mouse dragging event, completely unrelated to dragging shell data from explorer. If you want to receive drag events then registering for `WM_DROPFILES` with `DragAcceptFiles` is not enough as this only gives you the final drop event, no dragging. You need to follow [Transferring Shell Objects with Drag-and-Drop and the Clipboard](https://msdn.microsoft.com/en-us/library/windows/desktop/bb776905(v=vs.85).aspx) by implementing `IDropTarget` interface. – Ondrej Kelle Sep 05 '16 at 14:02
  • The only difference regarding the OS will be your form will not be sent a wm_setcursor although the mouse pointer is hovering on your form. Other than that there are no additional/special messages or anything before wm_dropfiles is sent. – Sertac Akyuz Sep 05 '16 at 17:38
  • @GuidoG, please don't lead the OP astray. COM drag and drop does not trigger OnDragOver events. That's Delphi's internal drag and drop that does that, The Delphi implementation has nothing to do with COM drag and drop. – Johan Sep 05 '16 at 19:16
  • @Johan where do I do that ? can you show me where I mention com drag and drop and where I say anything that leads hem astray ? I only wanted to help and after he found out his event did not work I told hem to change his question to why it does not work, how does that leads him astray ? Please read and understand comments before you comment on them – GuidoG Sep 06 '16 at 06:09
  • @GuidoG Time to stop digging an even deeper hole. Regarding the original comment over debugging techniques ShowMessage is just as ineffective as IDE. Both will interact with drag modal loop. And as for CreateWnd and DestroyWnd that code is sound. You should learn about VCL window re-creation. Johan's comments were spot on. – David Heffernan Sep 06 '16 at 06:23
  • @DavidHeffernan Please read and understand comments before commenting on them. Johans comment is correct on what he said on OnDragOver event, but was wrong in regards that I am leading the op into that direction or any direction at all. Misunderstanding of comments seems to happen a lot here and being rude about it does not help. But lets not go into discussion about it there is nothing to gain there. – GuidoG Sep 06 '16 at 06:52
  • @Guido I'm afraid that you made a number of errors here and seem to be reluctant to admit that. You have made repeated erroneous and misleading statements. My advice to anybody reading this is to simply ignore every comment you made here. – David Heffernan Sep 06 '16 at 06:57
  • @DavidHeffernan I could go into discussion here but I have better things to do than that. Feel free to write anything about me or my comments what you want. – GuidoG Sep 06 '16 at 07:13
  • @Guido I certainly won't write about you. But I will continue to feel free to write about what anyone posts here. You likewise. You might like to learn about VCL window re-creation though. That knowledge will be useful to you. – David Heffernan Sep 06 '16 at 07:18

1 Answers1

4

The problem
Delphi's concept of Drag'n'drop is not related to COM Drag and drop at all.
Borland implemented a light-weight version for dragging and dropping within the same application.
This works great and very efficient, but does not support DnD operations between applications. COM drag and drop requires you to register a drop target with the OS and accept relevant mouse messages. At no point will a COM drag&drop ever generate an standard OnDragOver event.
I fear the documentation is quite misleading when it does not make clear this source of confusion.

You are mixing Windows message based code TPanel.WMDropFiles(var Message: TWMDropFiles) with Borland's implementation for intra-application use only: TfrmMain.panFileDropDragOver(...)
The two options exist in parallel universes.
If you want to do the COM way you need to go COM all the way.

The solution
The WMDropFiles option is still a 'light-weight' solution before you go full COM and need to implement IDropTarget and all the complexity that entails.

My answer to your question is to not invent your own drag and drop but to go on the intertubes and download: https://github.com/DelphiPraxis/The-Drag-and-Drop-Component-Suite-for-Delphi

This is the up to date version of Anders Melander's famous suite which used to be at: http://melander.dk/delphi/dragdrop/

This implements COM based drag and drop and solves all your problems in one go.
It is also a fine example of beautiful code in its own right.
Take special note of the demos. The shelldragdrop stuff should cover your use case.

Would you like to know more?
http://delphi.about.com/od/vclusing/a/dragdrop.htm

Johan
  • 74,508
  • 24
  • 191
  • 319