Draw polygon on Image - delphi

I've been searching this quite a while but couldn't get the answer.
I want to draw a polygon on an image, but I want to do this with by creating points;
With the MouseCursor create this specific points, and with a button draw a line along these points;
I found this:
var
Poly: array of TPoint;
begin
// Allocate dynamic array of TPoint
SetLength(Poly, 6);
// Set array elements
Poly[0] := Point(10, 10);
Poly[1] := Point(30, 5);
Poly[2] := Point(100, 20);
Poly[3] := Point(120, 100);
Poly[4] := Point(50, 120);
Poly[5] := Point(10, 60);
// Pass to drawing routine
Canvas.Polygon(Poly);
// Redim if needed
SetLength(Poly, 7);
Poly[6] := Point(1, 5);
// Pass to drawing routine
Canvas.Polygon(Poly);
end;
This is what I want, but the difference is the Point[1], Point[2], etc is given by the user with a MouseEvent.

You might superimpose a Paintbox over your image and use a code like this
unit Unit3;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ExtCtrls, StdCtrls;
type
TPointArray=array of TPoint;
TForm3 = class(TForm)
Image1: TImage;
PaintBox1: TPaintBox;
Button1: TButton;
procedure PaintBox1MouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
procedure PaintBox1Paint(Sender: TObject);
procedure Button1Click(Sender: TObject);
private
{ Private-Deklarationen }
FPointArray:TPointArray;
public
{ Public-Deklarationen }
end;
var
Form3: TForm3;
implementation
{$R *.dfm}
procedure TForm3.Button1Click(Sender: TObject);
begin
PaintBox1.Visible := false;
Image1.Canvas.Polygon(FPointArray);
end;
procedure TForm3.PaintBox1MouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
SetLength(FPointArray,Length(FPointArray)+1);
FPointArray[High(FPointArray)].X := X;
FPointArray[High(FPointArray)].Y := Y;
Paintbox1.Invalidate;
end;
procedure TForm3.PaintBox1Paint(Sender: TObject);
var
i:Integer;
begin
PaintBox1.Canvas.Brush.Style := bsClear; //as suggested by TLama
PaintBox1.Canvas.Polygon(FPointArray);
for I := 0 to High(FPointArray) do
begin
PaintBox1.Canvas.TextOut(FPointArray[i].X-5,FPointArray[i].y-5,IntToStr(i));
end;
end;
end.

Make an array of points managed by your form. Declare a dynamic-array field in your form class:
private
FPoly: array of TPoint;
In your OnClick event, lengthen the array and append a new coordinate to it:
procedure TFruitForm.ImageClick(Sender: TObject);
var
p: TPoint;
begin
p := ...;
SetLength(FPoly, Length(FPoly) + 1);
FPoly[High(FPoly)] := p;
end;
To assign p, see How do I get the coordinates of the mouse when a control is clicked?
Instead of an array, you might also consider using a generic list: TList<TPoint>.

Related

Apply color filter to a bitmap

I would need to color an image as in the example below.
I would need to apply this transformation in memory, after loading the image from a file.
An example of what I would like to achieve can be found at the following link (from which I took the attached image). Another site that implements the functionality that interests me: link
The color of the filter must be customizable.
I also have the ImageEn libraries available from which I started to do some tests, using the CastColorRange function, which however does not give me the expected result
var
FIMageEn: TImageEn;
...
procedure TTest.ApplyColorMask(const ARGBFilter: TRGB);
begin
FIMageEn.Proc.CastColorRange(FProcOverrideColorStartRange, // BeginColor
FProcOverrideColorEndRange, // EndColor
ARGBFilter); // Filter
end;
The problem with the piece of code shown above is that the function requires a range of colors in rgb format, but since the images are all different from each other, I don't know what range to set
You don't need a third-party library for this.
It looks like the desired transformation is to set the per-pixel hue (H) to a fixed value, preserving saturation (S) and value (V in the HSV colour model).
So, you merely need some RGB<->HSV conversion functions. Personally, I use my own, but I bet you can find plenty examples on the web.
Having access to such conversion functions, the rest is easy:
unit Unit6;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs;
type
TForm1 = class(TForm)
procedure FormResize(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure FormPaint(Sender: TObject);
procedure FormMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
procedure FormMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
protected
private
FBitmap, FBitmap2: TBitmap;
FX: Integer;
public
procedure WMEraseBkgnd(var Message: TWMEraseBkgnd); message WM_ERASEBKGND;
end;
var
Form1: TForm1;
implementation
uses
Math, ascolors;
{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject);
begin
FBitmap := TBitmap.Create;
FBitmap.LoadFromFile('K:\sample.bmp');
FBitmap2 := TBitmap.Create;
FBitmap2.Assign(FBitmap);
FBitmap2.PixelFormat := pf32bit;
{$POINTERMATH ON}
for var y := 0 to FBitmap2.Height - 1 do
begin
var sl: PRGBQuad := FBitmap2.ScanLine[y];
for var x := 0 to FBitmap2.Width - 1 do
begin
var ColorRgb := TRGB.Create(sl[x].rgbRed / 255, sl[x].rgbGreen / 255, sl[x].rgbBlue / 255);
var ColorHsv := THSV(ColorRgb);
ColorHsv.Hue := 0;
ColorRgb := TRGB(ColorHsv);
sl[x].rgbRed := Round(255 * ColorRgb.Red);
sl[x].rgbGreen := Round(255 * ColorRgb.Green);
sl[x].rgbBlue := Round(255 * ColorRgb.Blue);
end;
end;
FX := FBitmap.Width div 2;
ClientWidth := FBitmap.Width;
ClientHeight := FBitmap.Height;
end;
procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
FX := X;
Invalidate;
end;
procedure TForm1.FormMouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer);
begin
if csLButtonDown in ControlState then
begin
FX := X;
Invalidate;
end;
end;
procedure TForm1.FormPaint(Sender: TObject);
begin
BitBlt(
Canvas.Handle,
0,
0,
Min(FBitmap.Width, FX),
FBitmap.Height,
FBitmap.Canvas.Handle,
0,
0,
SRCCOPY
);
BitBlt(
Canvas.Handle,
FX,
0,
Max(0, FBitmap.Width - FX),
FBitmap.Height,
FBitmap2.Canvas.Handle,
FX,
0,
SRCCOPY
);
end;
procedure TForm1.FormResize(Sender: TObject);
begin
Invalidate;
end;
procedure TForm1.WMEraseBkgnd(var Message: TWMEraseBkgnd);
begin
Message.Result := 1;
end;
end.

Animated Ellipse Points

I am using LineDDA to draw animated selection:
procedure TFormMain.DrawMarchingAnts;
begin
AMarchingAntsCounter := AMarchingAntsCounterStart;
// Use LineDDA to draw each of the 4 edges of the rectangle
LineDDA(AMarchingAntsPointA.X, AMarchingAntsPointA.Y, AMarchingAntsPointB.X, AMarchingAntsPointA.Y,
#MarchingAnts, LongInt(
AMarchingAntsCanvas));
LineDDA(AMarchingAntsPointB.X, AMarchingAntsPointA.Y, AMarchingAntsPointB.X, AMarchingAntsPointB.Y,
#MarchingAnts, LongInt(
AMarchingAntsCanvas));
LineDDA(AMarchingAntsPointB.X, AMarchingAntsPointB.Y, AMarchingAntsPointA.X, AMarchingAntsPointB.Y,
#MarchingAnts, LongInt(
AMarchingAntsCanvas));
LineDDA(AMarchingAntsPointA.X, AMarchingAntsPointB.Y, AMarchingAntsPointA.X, AMarchingAntsPointA.Y,
#MarchingAnts, LongInt(
AMarchingAntsCanvas));
if AMarchingAntsPointB.X > AMarchingAntsPointA.X then
ARubberbandVisible := True
else
ARubberbandVisible := False;
end;
Is there a function to add animated ellipses to the corners of the rect for grip points?
You want an animated "marching ants" circle? Then create a custom pen style. For example, as follows:
unit Unit1;
interface
uses
Windows, Classes, Graphics, Controls, Forms, ExtCtrls, Math;
type
TForm1 = class(TForm)
Timer1: TTimer;
procedure FormPaint(Sender: TObject);
procedure Timer1Timer(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
FMarkBrush: LOGBRUSH;
FMarkPen: HPEN;
FPenStyle: array[0..1] of Integer;
FStartAngle: Single;
end;
implementation
{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject);
begin
FPenStyle[0] := 4;
FPenStyle[1] := 4;
FMarkBrush.lbStyle := BS_SOLID;
FMarkBrush.lbColor := ColorToRGB(clBlue);
FMarkPen := ExtCreatePen(PS_GEOMETRIC or PS_USERSTYLE, 1, FMarkBrush, 2,
#FPenStyle);
Canvas.Pen.Handle := FMarkPen;
end;
procedure TForm1.FormPaint(Sender: TObject);
var
X: Integer;
Y: Integer;
begin
Canvas.FillRect(Rect(0, 0, 50, 50));
X := Round(25 * (1 + Cos(FStartAngle)));
Y := Round(25 * (1 + Sin(FStartAngle)));
Canvas.Arc(0, 0, 50, 50, X, Y, X, Y);
end;
procedure TForm1.Timer1Timer(Sender: TObject);
begin
FStartAngle := FStartAngle + DegToRad(5);
Invalidate;
end;
end.

Showing a TImage partially Dim

I'm trying to make a cropping tool that will look as follow:
Original Image:
Crop tool - This is what I want:
Notice that the cropping area is showing the original colors, and around the colors are dim.
What I did is to place a TShape over my TImage with properties:
object Shape1: TShape
Brush.Color = clSilver
Pen.Mode = pmMask
Pen.Style = psDot
end
I plan to use the TShape to make the re-sizing/coping control.
This is how it looks in Delphi:
As you can see, it does not looks good (colors palette looks dithered), but the main problem that I need the dim area to be around the crop area, not in the center. I have tried to cover the whole TImage with another TShpae, tried different Pen.Mode combinations but there are no good results, and I think my method/approach is bad.
Do you have any ideas on how to achieve the desired behavior?
a little part is missing here, but should not be a problem to add...
unit Unit3;
// 20121108 by Thomas Wassermann
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ExtCtrls, jpeg;
type
TForm3 = class(TForm)
Image1: TImage;
PaintBox1: TPaintBox;
procedure FormCreate(Sender: TObject);
procedure PaintBox1Paint(Sender: TObject);
procedure PaintBox1MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
procedure PaintBox1MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
private
{ Private-Deklarationen }
FDownPoint, FCurrentPoint: TPoint;
public
{ Public-Deklarationen }
end;
var
Form3: TForm3;
implementation
uses Math;
{$R *.dfm}
procedure TForm3.FormCreate(Sender: TObject);
begin
PaintBox1.BringToFront;
end;
type
pRGBQuadArray = ^TRGBQuadArray;
TRGBQuadArray = ARRAY [0 .. $EFFFFFF] OF TRGBQuad;
Procedure SetAlpha(bmp: TBitMap; Alpha: Byte; R: TRect);
var
pscanLine32: pRGBQuadArray;
i, j: Integer;
begin
bmp.PixelFormat := pf32Bit;
bmp.HandleType := bmDIB;
bmp.ignorepalette := true;
bmp.alphaformat := afDefined;
for i := 0 to bmp.Height - 1 do
begin
pscanLine32 := bmp.Scanline[i];
for j := 0 to bmp.Width - 1 do
begin
if (j >= R.Left) and (j <= R.Right) and (i >= R.Top) and (i <= R.Bottom) then
begin
pscanLine32[j].rgbReserved := 0;
pscanLine32[j].rgbBlue := 0;
pscanLine32[j].rgbRed := 0;
pscanLine32[j].rgbGreen := 0;
end
else
begin
pscanLine32[j].rgbReserved := Alpha;
pscanLine32[j].rgbBlue := Alpha;
pscanLine32[j].rgbRed := Alpha;
pscanLine32[j].rgbGreen := Alpha;
end;
end;
end;
end;
procedure TForm3.PaintBox1MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
FDownPoint.X := X;
FDownPoint.Y := Y;
FCurrentPoint := FDownPoint;
PaintBox1.Invalidate;
end;
procedure TForm3.PaintBox1MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
begin
if ssLeft in Shift then
begin
FCurrentPoint.X := X;
FCurrentPoint.Y := Y;
PaintBox1.Invalidate;
end;
end;
procedure TForm3.PaintBox1Paint(Sender: TObject);
var
bmp: TBitMap;
SelRect: TRect;
begin
bmp := TBitMap.Create;
try
bmp.Width := PaintBox1.Width;
bmp.Height := PaintBox1.Height;
if (FCurrentPoint.X = FDownPoint.X) and (FCurrentPoint.Y = FDownPoint.Y) then
SelRect := PaintBox1.BoundsRect
else
begin
SelRect.Left := Min(FCurrentPoint.X, FDownPoint.X);
SelRect.Top := Min(FCurrentPoint.Y, FDownPoint.Y);
SelRect.Right := Max(FCurrentPoint.X, FDownPoint.X);
SelRect.Bottom := Max(FCurrentPoint.Y, FDownPoint.Y);
end;
SetAlpha(bmp, 140, SelRect);
PaintBox1.Canvas.Draw(0, 0, bmp);
finally
bmp.Free;
end;
end;
end.
The attempt on this solution is to use a overlying paintbox, same clientrect as the image, for all the drawing and selection. By using the coordinates generated by mouse/down/move a semitransparent bitmap is created, which is full transparent in the selected rect. After generation it's painted on the paintbox. Further paintings could be done there e.g. frames, anchors, crosshair. Any user action would have to be caught in mousedown, depending of the selected part ,e.g. an anchor a sizing of the rect could be done.
Usually I'd prefer GDI+ for requests like this, but as shown, no additional units are required. Source: http://www.bummisoft.de/download/transparenteauswahl.zip

FireMonkey PenMode equivalent - DrawLine

I am playing around with FireMonkey simply to test out a couple of things. One of which is implement "very simple" drawing on a canvas. eg Line, Rectangle etc...
First question is, is there an equivalent of the graphex demo supplied for VCL for FireMonkey?
Otherwise, for the purposes of the exercise, I'm trying to replicate that demo in FireMonkey and just now, the line drawing. I can get the line drawing working in so much as when I move the mouse around the line draws where expected. Unfortunately I can't get it to automatically erase the old line that was drawn at the previous point where the mouse was. This seems to be taken care of by the TPenMode property of the TPen property which is - so much as I can tell - a TStroke property in FireMonkey. ie setting the property to pmXor while drawing (moving the mouse) and then setting it to pmCopy when complete.
How would I do something similar with FireMonkey?
Here's the routine that's called during a MouseMove event of a TImage:
FDrawSurface.Bitmap.Canvas.BeginScene;
try
case FShapeToDraw of
doLine:
begin
FDrawSurface.Bitmap.Canvas.DrawLine(PointF(TopLeft.X, TopLeft.Y), PointF(BottomRight.X, BottomRight.Y), 100);
end;
end;
finally
FDrawSurface.Bitmap.Canvas.EndScene;
FDrawSurface.Bitmap.BitmapChanged;
end;
FDrawSurface is a TImage. TopLeft is a TPoint which contains the X and Y of where the mouse was as capture in an OnMouseDown event of the TImaeg and BottomRight is the current X and Y coords from the OnMouseMove event.
So every time I move a mouse, I get "addtional" lines on my image.
Thanks
AFAIK, there's no mode like this with FMX...
Moreover, what you draw on the canvas is not really saved (if you know how to directly save it, explain me in a comment): if you move your form outside your desktop, and bring it back, the canvas is cleaned...
So, to implement the graphex demo, you have to code it with others technics..
For example, use a TBitmap to store your real "image" and only use the canvas for the "preview"...
unit main;
interface
uses
System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
FMX.Types, FMX.Controls, FMX.Forms, FMX.Dialogs, FMX.Objects;
type
TfrmMain = class(TForm)
recBoard: TRectangle;
btnCopy: TButton;
Image1: TImage;
procedure recBoardMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Single);
procedure recBoardMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Single);
procedure recBoardMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Single);
procedure recBoardMouseInOut(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure btnCopyClick(Sender: TObject);
procedure FormDestroy(Sender: TObject);
private
{ Private declarations }
bmp: TBitmap;
pFrom, pTo: TPointF;
public
{ Public declarations }
end;
var
frmMain: TfrmMain;
implementation
{$R *.fmx}
procedure TfrmMain.btnCopyClick(Sender: TObject);
begin
Image1.Bitmap.Assign(bmp);
end;
procedure TfrmMain.FormCreate(Sender: TObject);
begin
pFrom := PointF(-1, -1);
bmp := TBitmap.Create(Round(recBoard.Width), Round(recBoard.Height));
end;
procedure TfrmMain.FormDestroy(Sender: TObject);
begin
bmp.Free;
end;
procedure TfrmMain.recBoardMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Single);
begin
if Button = TMouseButton.mbLeft then
begin
pFrom := PointF(X, Y);
pTo := PointF(X, Y);
end;
end;
procedure TfrmMain.recBoardMouseInOut(Sender: TObject);
begin
pFrom := PointF(-1, -1);
end;
procedure TfrmMain.recBoardMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Single);
begin
if ((pFrom.X <> -1) and (pFrom.X <> -1)) then
with recBoard.Canvas do
begin
BeginScene;
if ssLeft in Shift then
begin
FillRect(RectF(0, 0, bmp.Width, bmp.Height), 0, 0, [], 255);
DrawBitmap(bmp, RectF(0, 0, bmp.Width, bmp.Height), RectF(0, 0, bmp.Width, bmp.Height), 255);
Stroke.Color := claBlue;
pTo := PointF(X, Y);
DrawEllipse(RectF(pFrom.X, pFrom.Y, pTo.X, pTo.Y), 255);
end;
EndScene;
end;
Self.Caption := Format('(%0.0f;%0.0f)', [X, Y]);
end;
procedure TfrmMain.recBoardMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Single);
begin
with bmp.Canvas do
begin
BeginScene;
DrawEllipse(RectF(pFrom.X, pFrom.Y, pTo.X, pTo.Y), 255);
EndScene;
end;
pFrom := PointF(-1, -1);
end;
end.
What I ended up doing - based on insight from Whiler above, was storing the bitmap's state at the start of the "draw routine" (ie on mouse down), then on MouseMove, before I render the new Line (in this example), I restore the state and then draw the new line...
procedure TFMXDrawSurface.DrawSurfaceMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Single);
begin
FOrigin := PointF(X, Y);
FMovePt := PointF(X, Y);
FPrevPt := PointF(X, Y);
FDrawing := True;
FTempDrawbitmap.Assign(FDrawSurface.Bitmap);
end;
procedure TFMXDrawSurface.DrawSurfaceMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Single);
begin
if FDrawing then
begin
DrawShape(FOrigin, FMovePt);
FMovePt := PointF(X, Y);
DrawShape(FOrigin, FMovePt);
FPrevPt := PointF(X, Y);
end;
end;
procedure TFMXDrawSurface.DrawShape(TopLeft, BottomRight: TPointF);
var
R: TRectF;
begin
FDrawSurface.Bitmap.Canvas.BeginScene;
try
case FShapeToDraw of
doLine:
begin
// restore canvas to initial state so we don't keep old movement data around
R.TopLeft := PointF(0.0, 0.0);
R.BottomRight := PointF(FDrawSurface.Width, FDrawSurface.Height);
FDrawSurface.Bitmap.Canvas.DrawBitmap(FTempDrawBitmap, R, R, 100);
FDrawSurface.Bitmap.Canvas.RestoreState(FDrawState);
FDrawSurface.Bitmap.Canvas.DrawLine(PointF(TopLeft.X, TopLeft.Y), PointF(BottomRight.X, BottomRight.Y), 100);
end;
end;
finally
FDrawSurface.Bitmap.Canvas.EndScene;
FDrawSurface.Bitmap.BitmapChanged;
end;
end;
It works, but I don't know if it's the "right" way or not...

How to drag a thumbnail from JvtThumbview?

I am writing a WYSIWYG type of editor program in which the user can drag image thumbnails onto an editor surface (TPanel) and then create a PDF by rendering the editor surface onto the PDF.
On my TPanel, I have a TImage which the user can resize and move. I am using TSizeCtrl for this.
I have a TJvThumbview which is being loaded with images from a disk folder.
I want to accomplish drag-drop from the JvThumbview onto the TImage - but cannot do this.
Please can someone detail how I would accomplish this?
Thanks so much in advance.
I cannot resist.
My demo project consists of:
one TJvThumbView and
one TImage
Dragging is achieved by:
starting the drag operation when the user mouse-downs on the thumb view,
managing the dragged image by a TDragObject derivative,
drawing the dragged image when the drag object says the drag operation ended on the TImage.
This is how it could look like:
unit Unit1;
interface
uses
Classes, Graphics, Controls, Forms, JvExForms, JvBaseThumbnail, JvThumbViews,
ExtCtrls;
type
TMyDragObject = class(TDragControlObjectEx)
private
FDragImages: TDragImageList;
FPictureToDrag: TPicture;
protected
function GetDragImages: TDragImageList; override;
procedure Finished(Target: TObject; X, Y: Integer;
Accepted: Boolean); override;
public
constructor CreateFromThumbView(ThumbView: TJvThumbView);
destructor Destroy; override;
end;
TForm1 = class(TForm)
JvThumbView1: TJvThumbView;
Image1: TImage;
procedure FormCreate(Sender: TObject);
procedure JvThumbView1MouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
procedure JvThumbView1StartDrag(Sender: TObject;
var DragObject: TDragObject);
procedure Image1DragOver(Sender, Source: TObject; X, Y: Integer;
State: TDragState; var Accept: Boolean);
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject);
begin
// Fill our image list with arbitrary images
if JvThumbView1.Directory = '' then
JvThumbView1.Directory := 'C:\Users\Public\Pictures\Sample Pictures';
// Style all controls for showing the drag image if Delphi version is D7 or
// lower. See also comment in TMyDragObject.CreateFromThumbView
JvThumbView1.ControlStyle := JvThumbView1.ControlStyle +
[csDisplayDragImage];
Image1.ControlStyle := Image1.ControlStyle + [csDisplayDragImage];
ControlStyle := ControlStyle + [csDisplayDragImage];
end;
procedure TForm1.Image1DragOver(Sender, Source: TObject; X, Y: Integer;
State: TDragState; var Accept: Boolean);
begin
// The destination image component accepts all drag operations
Accept := True;
end;
procedure TForm1.JvThumbView1MouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
// If mouse down on a thumb...
if JvThumbView1.SelectedFile <> '' then
// then let's start dragging
JvThumbView1.BeginDrag(False, Mouse.DragThreshold);
end;
procedure TForm1.JvThumbView1StartDrag(Sender: TObject;
var DragObject: TDragObject);
begin
// DragObject will automatically be destroyed when necessary when it's
// derived from TDragControlObjectEx
DragObject := TMyDragObject.CreateFromThumbView(JvThumbView1);
end;
{ TMyDragObject }
const
DragImageSize = 100;
constructor TMyDragObject.CreateFromThumbView(ThumbView: TJvThumbView);
begin
inherited Create(ThumbView);
// This is the picture the user will drag around
FPictureToDrag := TPicture.Create;
FPictureToDrag.LoadFromFile(ThumbView.SelectedFile);
// We want a nice drag image, but this property is only available in >D7
{ AlwaysShowDragImages := True; }
end;
destructor TMyDragObject.Destroy;
begin
FDragImages.Free;
FPictureToDrag.Free;
inherited Destroy;
end;
procedure TMyDragObject.Finished(Target: TObject; X, Y: Integer;
Accepted: Boolean);
begin
// Finished dragging
inherited Finished(Target, X, Y, Accepted);
// If we are over an Image component, then draw the picture
if Accepted and (Target is TImage) then
TImage(Target).Canvas.StretchDraw(Bounds(X, Y, DragImageSize,
DragImageSize), FPictureToDrag.Graphic);
end;
function TMyDragObject.GetDragImages: TDragImageList;
var
DragImage: TBitmap;
begin
if FDragImages = nil then
begin
FDragImages := TDragImageList.Create(nil);
// Set dimensions of drag image list
FDragImages.Width := DragImageSize;
FDragImages.Height := DragImageSize;
// Prepare drag image
DragImage:= TBitmap.Create;
try
DragImage.Width := DragImageSize;
DragImage.Height := DragImageSize;
DragImage.Canvas.StretchDraw(Rect(0, 0, DragImage.Width,
DragImage.Height), FPictureToDrag.Graphic);
FDragImages.AddMasked(DragImage, clWhite);
finally
DragImage.Free;
end;
end;
Result := FDragImages;
end;
end.

Resources