From: tnomad@digital.net
Subject: Drag/Drop and Delphi Information
Date: 28 Jun 1995 12:43:55 GMT

Hey all,

I though you would be interested in a recent discovery I made regarding
Drag and Drop in Delphi.  My requirement was to implement a similar
interface to Dragging and Dropping as is found in File Manager, with
respect to using the CTRL key to specify copying.

My first (and very unsuccessful) pass was to use GetKeyboardState to
examine the keyboard state and see if the CTRL key was depressed.
There were two problems with this approach: 
    1) This function does not seem to return consistent values.
    2) When dragging and dropping, mouse capture is set on the
    control.  The OnKeyDown/OnKeyUp methods are not triggered during
    dragging.

My second approach was to come up with a way to intercept the Windows
message when the dragging was taking place.  The only way to do this is
to subclass the control, and override the WndProc method.  I created a
new property (WndProcFunction), that will be called when the property
is assigned.  In my subclass, I override the WndProc, call
WndProcFunction if it is assigned, then call the inherited version:


type

  TMessageEvent = procedure(Sender: TObject; Message: TMessage) of object;

...

  MyControl = class(subcontrol)
    private
        FWndProcFunction: TMessageEvent;
    ...
    published
        property WndProcFunction: TMessageEvent
        					read FWndProcFunction
                            write FWndProcFunction;
    ...
    public
        procedure WndProc(var Message: TMessage); override;
    end

...

procedure MyControl.WndProc(var Message: TMessage);
begin
	if Assigned(FWndProcFunction) then
    	WndProcFunction(self, Message);
    inherited WndProc(Message);
end;



In my application (where I implement this class), I use the object
browser to create the following function:


procedure TViewRetrieval.ViewGridWndProcFunction(Sender: TObject;
  Message: TMessage);
begin
	case Message.Msg of
		WM_KEYDOWN, WM_KEYUP: DoProcessKey(Sender, TWMKey(Message));
	end;
end;

I then created DoProcessKey as follows (note: crDragCopy is my own
cursor):

procedure TViewRetrieval.DoProcessKey(Sender: TObject; var Message: TWMKey);
var
	ShiftState: TShiftState;
    pt: TPoint;
begin
   	ShiftState := KeyDataToShiftState(Message.KeyData);
	if (ShiftState = [ssCtrl]) then
		ViewGrid.DragCursor := crDragCopy
	else
		ViewGrid.DragCursor := crDrag;
    if ViewGrid.Dragging then
    begin
    	GetCursorPos(pt);
        SetCursorPos(pt.x, pt.y);	{Causes the cursor to be redrawn}
    end;
end;


************************************
*           The Nomad              *
*        tnomad@digital.net        *
************************************

-------------------------------------------------------------------------------

From: mduncan@wpo.borland.com (Mark Duncan)
Subject: Re: Drag/Drop and Delphi Information
Date: 28 Jun 1995 21:01:31 GMT

Here's how I would do it:

Initiate the drag (call BeginDrag method of the dragged control) in that control's
OnMouseDown event, which passes in information about the button and keyboard states.

Procedure TForm1.SourceFileListBoxMouseDown(Sender: TObject; Button: tMouseButton;
  Shift : TShiftState; X, Y: Integer);
begin
  if (Button = mbLeft) and (ssCtrl in Shift) 
  then with (Sender as TWinControl) do begin
     BeginDrag(True);
     .......           {init information about what files are selected, etc}
     FCopying := True; {a global boolean you declare to keep track of what kind of
  end;                  dragging is going on}
   

then in the OnDragDrop of the accepting control you would have something like:

TForm1.DestFileListBoxDragDrop(Sender, Source : TObject; X, Y : integer);
begin
  if (Source = SourceFileListBox) and (FCopying = True) 
  then ...... {do the copy}
end;

Mark
