Project source
Form source (Pascal)
Form source (DFM)
Project source: CursorTest.dpr |
program CursorTest; uses Forms, fmCursorTest in 'fmCursorTest.pas' {Form1}; {$R *.RES} begin Application.Initialize; Application.CreateForm(TForm1, Form1); Application.Run; end.Back to top |
Form source: fnCursorTest.pas |
unit fmCursorTest; { UnitOOPS OLE Drag and Drop Components - Example for using custom cursors for feedback during a drag operation. Last modified: 09/29/99} interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, FileCtrl, StdCtrls, uoole, ExtCtrls; 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); private { Private declarations } dragIcons: array[TDropEffect] of TIcon; 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; procedure TForm1.UOTextSource1GiveFeedback(Sender: TObject; effect: TDropEffect; var defCursors: Boolean); // Give feedback by overriding the standard cursors. // This is all you need to change the cursors - you just use SetCursor (a WinAPI // call) with some cursor handle. // In this sample, we get fancier than that - we dynamically draw a new set // of drag cursors at the start of each drag, to incorporate the file icon // and file name being dragged. begin defCursors := false; SetCursor(DragIcons[effect].Handle); end; procedure TForm1.FreeDragCursors; // Clean up the icons that are being used as drag cursors var aDe: TDropEffect; begin for aDe := low(TDropEffect) to pred(high(TDropEffect)) do begin if assigned(dragIcons[aDe]) then begin dragIcons[aDe].Free; dragIcons[aDe] := nil; end; end; end; procedure TForm1.InitializeDragCursors(isFile: boolean); // Each time we start a drag, we'll call this function. It constructs // a set of icons that we use as the drag cursors for each type of operation // (no drop, copy, move, link). In situations like this, Windows treats // cursor handles and icon handles the same. // Here, we're generating the cursors dynamically. We could, of course, use // custom cursors that didn't change at all over the course of the application, // in which case we'd just load them once from the resources. // isFile is true if we're dragging from the file list, false if we're dragging // from the directory list. const iHeight = 75; iWidth = 800; var aBMP: TBitmap; aDe: TDropEffect; ilDrag: TImageList; 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; // Create one icon for each operation for aDe := low(TDropEffect) to pred(high(TDropEffect)) do begin dragIcons[aDe] := TIcon.Create; end; // Make an image list. We use this since it has methods that allow us to stuff // a bitmap and mask color in, and get an icon out. 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; try // 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 // Hot-spot will be in the center of the icon/cursor // 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). See the FormCreate method // above for more information. DrawIcon(aBMP.Canvas.Handle, width div 2, 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, width div 2 + 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(width div 2 + 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, then extract it as an icon // into the appropriate element of dragIcons[]. ilDrag.AddMasked(aBMP, clOlive); ilDrag.GetIcon(ilDrag.Count-1, dragIcons[aDe]); end; end; finally aBMP.Free; end; finally ilDrag.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[crOLECopy] := LoadCursor(HInstance, 'CURCOPY'); Screen.Cursors[crOLEMove] := LoadCursor(HInstance, 'CURMOVE'); Screen.Cursors[crOLELink] := LoadCursor(HInstance, 'CURLINK'); Screen.Cursors[crOLENo] := LoadCursor(HInstance, 'CURNO'); // 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. 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 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; end.Back to top |
Form source: fmCursorTest.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 |