Project source
Form source (Pascal)
Form source (DFM)
Project source: CursorTest2.dpr |
program cursortest2; uses Forms, fmCursorTest2 in 'fmCursorTest2.pas' {Form1}; {$R *.RES} begin Application.Initialize; Application.CreateForm(TForm1, Form1); Application.Run; end.Back to top |
Form source: fnCursorTest2.pas |
unit fmCursorTest2; { UnitOOPS OLE Drag and Drop Components - Example 2 for using custom cursors for feedback during a drag operation. Last modified: 11/02/98} interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, FileCtrl, StdCtrls, uoole, ExtCtrls, rzcsintf; type TForm1 = class(TForm) UOTextSource1: TUOTextSource; UOTextTarget1: TUOTextTarget; Panel1: TPanel; Panel2: TPanel; DriveComboBox1: TDriveComboBox; DirectoryListBox1: TDirectoryListBox; FileListBox1: TFileListBox; Label1: TLabel; procedure UOTextSource1GiveFeedback(Sender: TObject; effect: TDropEffect; var defCursors: Boolean); procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); procedure FileListBox1MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); procedure UOTextSource1AfterDrop(Sender: TObject; Donor: TComponent; droppedOK: Boolean); procedure UOTextSource1CancelDrop(Sender: TObject); private { Private declarations } // dragIcons: array[TDropEffect] of TIcon; ilDrag: TImageList; currentEffectIndex: integer; procedure InitializeDragCursors(isFile: boolean); procedure FreeDragCursors; public { Public declarations } end; var Form1: TForm1; implementation uses ShellAPI, uoUtil; {$R *.DFM} {$R olecursors.res} const crOLENo = 1; crOLECopy = 2; crOLEMove = 3; crOLELink = 4; const iHeight = 75; iHd2 = iHeight div 2; iWidth = 500; procedure TForm1.UOTextSource1GiveFeedback(Sender: TObject; effect: TDropEffect; var defCursors: Boolean); // Give feedback. This is where we substitute our imagelist drag images // for the standard cursors. iHD2 is iHeight div 2, which is the y-position // of the cursor hotspot. We get called here every time the mouse moves or a // drop effect modifier key is pressed (e.g., Ctrl, Shift). var aPt: TPoint; begin defCursors := false; // We're going to paint our own cursors. if not defCursors then begin GetCursorPos(aPt); // Where are we? // If the drop effect has changed, we'll change images if (currentEffectIndex <> ord(effect)) then begin // Store the new drop effect index. currentEffectIndex := ord(effect); // Stop dragging ilDrag.EndDrag; // Set the new drag image to the correct index based on the // current drop effect. ilDrag.SetDragImage(ord(effect), 0, 0); // Begin dragging with the new one. The windows to specify is the // desktop window, since we could be dragging anywhere on the screen. // If you want to restrict this further, then only do it within the // bounds of a given window, and set defCursors = true otherwise. ilDrag.BeginDrag(GetDesktopWindow, aPt.X, aPt.Y-iHd2); end; // Either way, we'll move the image (may or may not have changed). ilDrag.DragMove(aPt.X, aPt.Y-iHd2); end; end; procedure TForm1.FreeDragCursors; // Clean up the drag image list, and reset the effect index begin if Assigned(ilDrag) then ilDrag.Free; CurrentEffectIndex := -1; end; procedure TForm1.InitializeDragCursors(isFile: boolean); // Each time we start a drag, we'll call this function. It constructs // a set of images and puts them in an image list (masked by clOlive). // The alternative to this sort of approach is to use standard Windows // cursors and calls to "SetCursor" within TUOTextSource.OnGiveFeedback. // In Win95, however, this limits you to standard (32x32) cursors sizes, // although you can get bigger ones in WinNT (see CursorTest.dpr). var aBMP: TBitmap; aDe: TDropEffect; aShFI: TShFileInfo; dragString: string; begin // For each operation, we'll just use the filename as the text if isFile then dragString := Filelistbox1.Filename else dragString := DirectoryListBox1.Directory; // Get the small icon for the file being dragged fillChar(aShfi, sizeOf(aShfi), 0); SHGetFileInfo(PChar(dragString), 0, aShFI, sizeOf(aShFI), SHGFI_ICON or SHGFI_SMALLICON); // Clear out the icons FreeDragCursors; // Make an image list to hold the drag images ilDrag := TImageList.Create(nil); // Make the size of each individual image large to accomodate long text. // We're only using half, since the hotspot is in the middle. ilDrag.Height := iHeight; ilDrag.Width := iWidth; // Make the temporary bitmap onto whose handle we'll draw the content that // will become the cursors. aBMP := TBitmap.Create; try aBMP.width := iWidth; aBMP.height := iHeight; with aBMP.Canvas, aBMP do begin // Loop over all drop effects (except scroll) for aDe := low(TDropEffect) to pred(high(TDropEffect)) do begin // Choose font settings // Use text in red for "no drop" case if aDe = deNone then Font.Color := clRed else Font.Color := clWindowText; // Fill the background with solid olive, the color we use as mask // This effectively "clears" the background, since the mask color // will be gone when we turn this into a cursor. Brush.Color := clOlive; Brush.Style := bsSolid; FillRect(Rect(0, 0, width, height)); // Draw the appropriate cursor. // Here, we've loaded some custom // cursors from olecursors.res (just the standard OLE cursors, taken // from OLE32.DLL using Resource Workshop). Their hotspots are all // at (0, 0). // See the FormCreate method above for more information. DrawIcon(aBMP.Canvas.Handle, 0, height div 2, Screen.Cursors[crOLENo + ord(aDe)]); // Draw the small file icon. // Use DrawIconEx rather than DrawIcon, since the latter appears to // insist on drawing even a small icon by stretching to the default // icon metrics. DrawIconEx(aBMP.Canvas.Handle, 16 , (height - GetSystemMetrics(SM_CYSMICON)) div 2, aShfi.hIcon, 0, 0, 0, 0, DI_NORMAL); // Draw the text string, on a clear background // Here we just draw the file name. We align it to the // icon, already drawn. Brush.Style := bsClear; TextOut(20 + GetSystemMetrics(SM_CXSMICON), (height - abs(Font.Height)) div 2, dragString); // Here's the action part of the procedure. Add the image to the // image list using clOlive as the mask. ilDrag.AddMasked(aBMP, clOlive); end; end; finally aBMP.Free; end; end; procedure TForm1.FormCreate(Sender: TObject); begin // Load the custom cursors defined on olecursurs.res. // They're actually just the standard OLE cursors from OLE32.DLL Screen.Cursors[crOLENo] := LoadCursor(HInstance, 'CURNO'); Screen.Cursors[crOLECopy] := LoadCursor(HInstance, 'CURCOPY'); Screen.Cursors[crOLEMove] := LoadCursor(HInstance, 'CURMOVE'); Screen.Cursors[crOLELink] := LoadCursor(HInstance, 'CURLINK'); // Drawing efficiency and flicker-minimization. currentEffectIndex := -1; // Trickery. If the form isn't itself an OLE drop target, we'll get the // standard "no drop" cursor, rather than our custom one. To get our custom // "no drop" cursor, we set up a dummy text target with the form as its // AcceptorControl, but that accepts no formats! UOTextTarget1.AcceptTextFormats := []; UOTextTarget1.AcceptorControl := Self; end; procedure TForm1.FormDestroy(Sender: TObject); begin // Clean up. FreeDragCursors; end; procedure TForm1.FileListBox1MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); // This is shared by FileListBox1 and DirectoryListBox1. // On mouse down, detect a drag. var aSL: TStringList; begin // Probably the best way to start a drag. No cursor changes happen // until you leave the drag rect. if DragDetect(Handle, ClientToScreen(POINT(X, Y))) then begin // Set up the drag cursors based on the current selection InitializeDragCursors(Sender = FileListBox1); // Do the drag with UOTextSource1 do begin Text := ''; // Don't pass any text. We're only passing custom formats. // Functions below expect a TStringList - make one. aSL := TStringList.Create; if (Sender = FileListBox1) then aSL.add(FileListBox1.FileName) else aSL.add(DirectoryListBox1.Directory); try CustomFormatData.Clear; // Pass file copy, move, link information CustomFormatData.AddFormat(IntToStr(CF_HDROP), uoHDropFromFileList('', aSL)); CustomFormatData.AddFormat('Shell IDList Array', uoShellIDListFromFileList('', aSL)); finally aSL.Free; end; Execute; // Start the drag operation end; end; end; procedure TForm1.UOTextSource1AfterDrop(Sender: TObject; Donor: TComponent; droppedOK: Boolean); begin // Tell the image list we're done dragging ilDrag.EndDrag; end; procedure TForm1.UOTextSource1CancelDrop(Sender: TObject); begin // Tell the image list we're done dragging ilDrag.EndDrag; end; end.Back to top |
Form source: fmCursorTest2.dfm |
object Form1: TForm1 Left = 312 Top = 196 BorderStyle = bsDialog Caption = 'Custom Drag Cursor Test' ClientHeight = 233 ClientWidth = 321 Color = clBtnFace Font.Charset = DEFAULT_CHARSET Font.Color = clWindowText Font.Height = -11 Font.Name = 'MS Sans Serif' Font.Style = [] OldCreateOrder = False OnCreate = FormCreate OnDestroy = FormDestroy PixelsPerInch = 96 TextHeight = 13 object Panel1: TPanel Left = 0 Top = 0 Width = 321 Height = 65 Align = alTop BevelOuter = bvNone BorderWidth = 5 TabOrder = 0 object Label1: TLabel Left = 5 Top = 5 Width = 311 Height = 55 Align = alClient Caption = 'Drag from either the directory list or the file list to any appl' + 'ication (e.g., Explorer) that accepts file drops. You can drag ' + 'shortcuts, copy, or move by holding down the appropriate keys (C' + 'trl, Shift, or both together). ' WordWrap = True end end object Panel2: TPanel Left = 0 Top = 65 Width = 321 Height = 168 Align = alClient BevelOuter = bvNone TabOrder = 1 object DriveComboBox1: TDriveComboBox Left = 4 Top = 3 Width = 145 Height = 19 DirList = DirectoryListBox1 TabOrder = 0 end object DirectoryListBox1: TDirectoryListBox Left = 4 Top = 27 Width = 145 Height = 136 FileList = FileListBox1 ItemHeight = 16 TabOrder = 1 OnMouseDown = FileListBox1MouseDown end object FileListBox1: TFileListBox Left = 154 Top = 3 Width = 161 Height = 160 ItemHeight = 13 TabOrder = 2 OnMouseDown = FileListBox1MouseDown end end object UOTextSource1: TUOTextSource OnGiveFeedback = UOTextSource1GiveFeedback DropEffects = [deCopy, deMove, deLink] Left = 96 Top = 177 end object UOTextTarget1: TUOTextTarget AcceptTextFormats = [] Left = 32 Top = 161 end endBack to top |