Thanks

BillDoorNZ for looking at my problem. My TCard class was deliberately not sub-classed from TImage to get more control over when Updates and Repaints occur - TImage seems to do a lot of this automatically. That way I can avoid a lot of unnecessary updates.
Your suggestion of doing all the drawing myself sounds rather daunting! Bear in mind I'm only new to this (6 weeks now).
Below are the relevant parts of the declarations of my card and card image window classes, together with the methods for sliding a card from A to B. I used the Windows API MoveWindow routine rather than setting Left and Top because when stepping through in the debugger the image window moved separately at the setting of Left and Top.
Any more comments (and solutions) would be greatly appreciated!!!
Bob
TCard = class(TGraphicControl)
private
FImage: TBitmap;
...
end;
TCardImageWin = class(TCustomControl)
private
FImage: TBitmap;
...
end;
procedure TCard.Slide(SlideSpeed: Integer; //Speed of the slide in pixels/sec
XEnd: Integer; //Horizontal position at the end of the slide
YEnd: Integer); //Vertical position at the end of the slide
var
_CardImageWin: TCardImageWin;
_XMax, _YMax: Integer;
_XMin, _YMin: Integer;
_XNext, _YNext: Integer;
_XSlide, _YSlide: Integer;
_XStart, _YStart: Integer;
_SlideDistance: Real;
_SlideDuration: Integer;
_TimeEnd: DWORD;
_TimeNow: DWORD;
_TimeStart: DWORD;
_TimeFromStart: Integer;
begin
{ Card image window created at a position outside the form }
_CardImageWin := TCardImageWin.Create(Owner);
try
{ Start of slide is from current X-Y card position }
_XStart := Left;
_YStart := Top;
{ Min-max X-Y bounds of card image during slide }
_XMin := Min(_XStart, XEnd);
_XMax := Max(_XStart, XEnd);
_YMin := Min(_YStart, YEnd);
_YMax := Max(_YStart, YEnd);
{ Change in X-Y position during slide }
_XSlide := XEnd - _XStart;
_YSlide := YEnd - _YStart;
{ Duration of the slide in ms }
_SlideDistance := Sqrt(Sqr(_XSlide) + Sqr(_YSlide));
_SlideDuration := Trunc((1000 * _SlideDistance) / SlideSpeed) + 1;
{ Set the image in the window to be the current card's image and move in front of the
card before hiding }
_CardImageWin.Image := Image;
_CardImageWin.BringToFront;
_CardImageWin.Move(_XStart, _YStart);
_CardImageWin.Show;
_CardImageWin.Update;
Hide;
{ Move card to end of the slide (ready to be made visible) }
Left := XEnd;
Top := YEnd;
{ Slide start and finish times in ms }
_TimeNow := GetTickCount;
_TimeStart := _TimeNow;
_TimeEnd := _TimeStart + DWORD(_SlideDuration);
{ Keep moving card image window until reach end of slide }
while (_TimeNow < _TimeEnd) do
begin
_TimeFromStart := _TimeNow - _TimeStart;
_XNext := ((_XSlide * _TimeFromStart) div _SlideDuration) + _XStart;
_YNext := ((_YSlide * _TimeFromStart) div _SlideDuration) + _YStart;
_XNext := EnsureRange(_XNext, _XMin, _XMax);
_YNext := EnsureRange(_YNext, _YMin, _YMax);
_CardImageWin.Move(_XNext, _YNext);
_TimeNow := GetTickCount;
end;
{ Finally set to end of slide position }
_CardImageWin.Move(XEnd, YEnd);
{ Make card visible before image window is destroyed }
Show;
finally
{ Delete image window }
_CardImageWin.Image := nil; //Unlink window image from Tcard image before freeing
_CardImageWin.Free;
end;
end;
procedure TCardImageWin.Move(ALeft: Integer;
ATop: Integer);
begin
MoveWindow(Self.Handle, ALeft, ATop, Width, Height, True);
Parent.Update; //Update invalidated parts of form
end;