我有一个带漫画书布局的.bmp图片。目前我的代码是这样的。如果我右键单击并按住鼠标按钮,我可以在漫画书页面上的其中一个框架周围绘制一个选框类型框。当我释放按钮时,它将放大到该帧。但它的瞬间。我希望它有动画效果。
因此,而不是将PicRect的值设置为“结束值”
PicRect.Left
PicRect.right
PicRect.top
PicRect.bottom
如下面的代码中所示,我需要一种方法来慢慢到达那里,某种类型的while循环一次设置这些值,直到它达到“最终值”但我不是100%肯定这个数学是如何工作的。也没有任何我的while循环尝试做任何事情,但放大太远。这是程序。
procedure TZImage.MouseUp(Button: TMouseButton; Shift: TShiftState;
X, Y: Integer);
var coef:Double;
t:integer;
begin
if FMouse=mNone then Exit;
if x>ShowRect.Right then x:=ShowRect.Right;
if y>ShowRect.Bottom then y:=ShowRect.Bottom;
if FMouse=mZoom then begin //calculate new PicRect
t:=startx;
startx:=Min(startx,x);
x:=Max(t,x);
t:=starty;
starty:=Min(starty,y);
y:=Max(t,y);
FMouse:=mNone;
MouseCapture:=False;
//enable the following if you want to zoom-out by dragging in the opposite direction}
{ if Startx>x then begin
DblClick;
Exit;
end;}
if Abs(x-startx)<5 then Exit;
if (x - startx < y - starty) then
begin
while (x - startx < y - starty) do
begin
x := x + 100;
startx := startx - 100;
end;
end
else if (x - startx > y - starty) then
begin
while (x - startx > y - starty) do
begin
y := y + 100;
starty := starty - 100;
end;
end;
//This is were it sets the zoom info. This is were
//I have to change to slowly get the PICRECT.Left/right/top/bottom
if (PicRect.Right=PicRect.Left)
then
coef := 100000
else
coef:=ShowRect.Right/(PicRect.Right-PicRect.Left);
PicRect.Left:=Round(PicRect.Left+startx/coef);
PicRect.Right:=PicRect.Left+Round((x-startx)/coef);
if (PicRect.Bottom=PicRect.Top)
then
coef := 100000
else
coef:=ShowRect.Bottom/(PicRect.Bottom-PicRect.Top);
PicRect.Top:=Round(PicRect.Top+starty/coef);
PicRect.Bottom:=PicRect.Top+Round((y-starty)/coef);
end;
if FMouse=mDrag then begin
FMouse:=mNone;
Canvas.Pen.Mode:=pmCopy;
Screen.Cursor:=crDefault;
end;
Invalidate;
end;
我相信这可以在上面的代码中完成。但也希望补充一下这有用。
type
TZImage = class(TGraphicControl)
private
FBitmap : TBitmap;
PicRect : TRect;
ShowRect : TRect;
FShowBorder : boolean;
FBorderWidth : integer;
FForceRepaint : boolean;
FMouse : (mNone, mDrag, mZoom);
FProportional : boolean;
FDblClkEnable : boolean;
startx, starty,
oldx, oldy : integer;
感谢您帮助我们开展此工作。
答案 0 :(得分:6)
我有一些建议;我不确定它们是否足以解决您的问题,但我希望它可以帮助您实现目标。
首先,你的while
循环正在进行大量有趣的小动作:
if (x - startx < y - starty) then
begin
while (x - startx < y - starty) do
begin
x := x + 100;
startx := startx - 100;
end;
end
else if (x - startx > y - starty) then
/* similar code */
请注意x - start == y - starty
案例被完全忽略了。我不知道这是否重要。
其次,这可能是在没有循环的情况下重写的。我在这里猜测,它需要一些测试,看看这是否正确,但这感觉就像正确的道路:
foo := (x - startx) - (y - starty)
if (foo > 200 || foo < -200)
bar = foo / 200 # I assume integer truncation
x += bar * 100
startx += bar * 100
我不完全确定你为什么试图让(x-startx) - (y-starty)
达到200之内;可能还有更好的东西。
这部分代码有点令人困惑:
if (PicRect.Right=PicRect.Left)
then
coef := 100000
else
coef:=ShowRect.Right/(PicRect.Right-PicRect.Left);
PicRect.Left:=Round(PicRect.Left+startx/coef);
PicRect.Right:=PicRect.Left+Round((x-startx)/coef);
if (PicRect.Bottom=PicRect.Top)
then
coef := 100000
else
coef:=ShowRect.Bottom/(PicRect.Bottom-PicRect.Top);
PicRect.Top:=Round(PicRect.Top+starty/coef);
PicRect.Bottom:=PicRect.Top+Round((y-starty)/coef);
end;
coef
是否应该从之前被覆盖?或者,您是应该计算coefx
和coefy
,然后选择(更大?更小?接近100000?)值来为.Left
,.Right
投放, .Top
和.Bottom
计算?我不得不认为,这样的代码,更有可能导致内容的笨拙延伸,从而可能会惹恼用户和作者。
现在,为了解决真正的原因,为什么你在这里,动画缩放 - 你可能需要彻底改变某些东西。我觉得你的while
循环可能是为了进行缩放,但是在 coef
计算后它们来了,所以我认为它们是用于其他东西的。但是,一旦你弄清楚确切地放置循环的位置来计算从“无缩放”到“最终缩放”范围内的不同coef
值,你还需要添加对重绘<的调用/ em>显示 - 或者,根据您的环境,可能需要每50毫秒添加一些定时器触发的回调代码,或者使用更新的coef
值进行重新绘制。
答案 1 :(得分:5)
由于两个问题,请勿使用while循环更新缩放级别:
Sleep
),代码也会在主线程中运行,而程序却没有响应。与sarnold和Elling已经说过:使用计时设备(例如TTimer
)在每个间隔执行一次总缩放操作。现在,有两种方法可以计算件:
我在this answer中使用了related question中的第二个解决方案,其中包含以下相关摘要:
procedure TZImage.Animate(Sender: TObject);
var
Done: Single;
begin
Done := (GetTickCount - FAnimStartTick) / FAnimDuration;
if Done >= 1.0 then
begin
FAnimTimer.Enabled := False;
FAnimRect := FCropRect;
end
else
with FPrevCropRect do
FAnimRect := Rect(
Left + Round(Done * (FCropRect.Left - Left)),
Top + Round(Done * (FCropRect.Top - Top)),
Right + Round(Done * (FCropRect.Right - Right)),
Bottom + Round(Done * (FCropRect.Bottom - Bottom)));
Invalidate;
end;
procedure TZImage.Zoom(const ACropRect: TRect);
begin
FPrevCropRect := FCropRect;
FAnimRect := FPrevCropRect;
FCropRect := ACropRect;
FAnimStartTick := GetTickCount;
FAnimTimer.Enabled := True;
end;
说明:
FCropRect
是新的缩放矩形,FPrevCropRect
是前一个矩形,FAnimRect
是两者之间的矩形,具体取决于动画的进度,FAnimStartTick
是通过调用Zoom
开始缩放操作的时间,Animate
被调用,Done
是动画进度的百分比,Invalidate
触发重绘,将图形绘制到FAnimRect
。答案 2 :(得分:3)
我写了一个你上一个问题的答案(一些人,可能是有意义的,stackoverflow主持人永久删除了)。
我之前的回答中的建议是你看看glflow代码示例:
http://code.google.com/p/glflow/
该示例使用GLScene库,并说明了图像加载,图像缩放和动画。
即使您不使用GLScene库,我认为您可以通过查看代码示例获得动画部分的一些灵感。
它的本质是你需要使用计时器来重绘。
首先将开始缩放级别和结束缩放级别之间的距离分成不连续的步骤。然后使用计时器循环执行这些步骤并对每一步重绘。
答案 3 :(得分:0)
我实际上是在这个项目上与Glen合作。我写了一些有问题的代码,所以我想澄清它的作用。我发表了评论,因为我很快把它扔了。这里的大部分代码都是通过我们发现的开放许可证来使用的。代码最初没有循环:
if (x - startx < y - starty) then
begin
while (x - startx < y - starty) do
begin
x := x + 100;
startx := startx - 100;
end;
end
else if (x - startx > y - starty) then
begin
while (x - startx > y - starty) do
begin
y := y + 100;
starty := starty - 100;
end;
end;
这是我添加的内容,因为原始代码没有像我们认为的那样工作,所以它被添加了。基本上你通过拖放选择区域。所选区域会被放大,但不是显示所选的整个区域,而是将x-startx或y-starty中的较小区域调整到视图区域。所以,试着澄清一下,如果你选择了50pix高和100pix宽的区域,它将缩放并适合50pix从上到下填充视图区域,但100像素被剪裁。两侧从观景区掉下来。因此,这里添加的代码是通过使两者中较小的两者中的较小者来解决问题。通过这样做,它实际上将视图适合两者中原来较大的那个,现在两者中较小的一个。这是一个令人难以置信的草率修复,但它的工作原理。您的方法也会为我们解决此问题,并且可能会以更好的方式执行此操作。这一切的最大问题是,如果该区域是一个非常大的区域选择,那么200pix可能实际上不应该修复差异。对于我们的目的,它可能适用于85%+,但不是全部,所以这段代码仍然需要工作。
你质疑的其他代码实际上是让我们疯狂的原因。在整个文档中完全没有评论,我们仍然试图将这一切完全拼凑起来。 coef实际上是让我发疯的原因。我甚至不确定它首先应该做什么。我确实试过了一个单独的coefx和coefy,这实际上打破了它。缩放框与预期的大不相同。据我所知,目前的方法不会增加奇怪的拉伸,为什么我不确定。
如果你想全面看一下,这里是我们正在使用的代码的链接。 http://www.torry.net/authorsmore.php?id=986该页面上的Zimage。
至于手头的实际问题,我们一开始并不清楚coef究竟做了什么,因此对它进行更改会导致我们破坏事物而不是以反复试验的方式工作。如果您不介意看看它,我们就可以确切地知道它能做什么,这样我们就可以将它更改为正确的值,并在此过程中摆脱我的slop代码。然后,这将允许我们前进到缩放动画。
添加有关动画的其他问题。这样做,这也允许我们在从图像上的一个缩放点移动到另一个缩放点时添加动画。对于我们的应用程序,它将从一个漫画小组到另一个,在下方或侧面,并且在大多数情况下也是不同的大小。加载左,右,上,下之间的值是否是显示该类动画的最佳方式?如果是这样,我认为这也适用于从完整图像移动到第一个缩放面板。