我喜欢在滚动框中平移图像后创建平滑的减慢滚动效果.就像在
maps.google.com中平移地图一样.我不知道它是什么类型,但完全相同的行为:当快速移动地图时,它不会立即停止,但是它开始变慢.
任何想法,组件,链接或样品?
解决方法
想法:
根据您的评论,它应该感觉像谷歌地图,因此拖动图像,图像应该坚持鼠标指针;到目前为止还没有特殊效果.但是在释放鼠标按钮时,图像需要在相同的方向上进一步移动(滚动框需要平移),并以逐渐的宽松速度从鼠标按钮释放时的拖动速度开始.
所以我们需要:
>当鼠标被按下时的拖动处理程序:OnMouseMove将工作,
>鼠标释放时的平移速度:在拖动操作期间,我们将使用定时器跟踪最新速度,
>在鼠标释放后仍然移动图像的东西:我们使用相同的计时器,
>更新GUI的方法:更新图像位置,滚动滚动框并更新滚动条位置.幸运的是,设置滚动框的滚动条的位置将会做到这一点,
>鼠标释放后逐渐降低速度的功能.我选择了一个简单的线性因子,但你可以试验一下.
建立:
>在表单上删除TScrollBox,为OnMouseDown,OnMouseMove和OnMouseUp创建事件处理程序,并将DoubleBuffered属性设置为True(这需要在运行时完成),
>在您的表单上删除TTimer,将其间隔设置为15毫秒(〜67赫兹刷新率),并为OnTimer创建事件处理程序,
>在滚动框上放一个TImage,加载图片,将大小设置为大(例如3200 x 3200),将Stretch设置为True,并将Enabled设置为False,使鼠标事件通过滚动框.
代码(滚动框):
- unit Unit1;
- interface
- uses
- Windows,SysUtils,Classes,Controls,Forms,JPEG,ExtCtrls,StdCtrls;
- type
- TForm1 = class(TForm)
- ScrollBox: TScrollBox;
- Image: TImage;
- TrackingTimer: TTimer;
- procedure ScrollBoxMouseDown(Sender: TObject; Button: TMouseButton;
- Shift: TShiftState; X,Y: Integer);
- procedure ScrollBoxMouseMove(Sender: TObject; Shift: TShiftState; X,Y: Integer);
- procedure ScrollBoxMouseUp(Sender: TObject; Button: TMouseButton;
- Shift: TShiftState; X,Y: Integer);
- procedure TrackingTimerTimer(Sender: TObject);
- procedure FormCreate(Sender: TObject);
- private
- FDragging: Boolean;
- FPrevScrollPos: TPoint;
- FPrevTick: Cardinal;
- FSpeedX: Single;
- FSpeedY: Single;
- FStartPos: TPoint;
- function GetScrollPos: TPoint;
- procedure SetScrollPos(const Value: TPoint);
- public
- property ScrollPos: TPoint read GetScrollPos write SetScrollPos;
- end;
- implementation
- {$R *.dfm}
- procedure TForm1.FormCreate(Sender: TObject);
- begin
- ScrollBox.DoubleBuffered := True;
- end;
- function TForm1.GetScrollPos: TPoint;
- begin
- with ScrollBox do
- Result := Point(HorzScrollBar.Position,VertScrollBar.Position);
- end;
- procedure TForm1.ScrollBoxMouseDown(Sender: TObject; Button: TMouseButton;
- Shift: TShiftState; X,Y: Integer);
- begin
- FDragging := True;
- FPrevTick := GetTickCount;
- FPrevScrollPos := ScrollPos;
- TrackingTimer.Enabled := True;
- FStartPos := Point(ScrollPos.X + X,ScrollPos.Y + Y);
- Screen.Cursor := crHandPoint;
- end;
- procedure TForm1.ScrollBoxMouseMove(Sender: TObject; Shift: TShiftState;
- X,Y: Integer);
- begin
- if FDragging then
- ScrollPos := Point(FStartPos.X - X,FStartPos.Y - Y);
- end;
- procedure TForm1.ScrollBoxMouseUp(Sender: TObject; Button: TMouseButton;
- Shift: TShiftState; X,Y: Integer);
- begin
- FDragging := False;
- Screen.Cursor := crDefault;
- end;
- procedure TForm1.SetScrollPos(const Value: TPoint);
- begin
- ScrollBox.HorzScrollBar.Position := Value.X;
- ScrollBox.VertScrollBar.Position := Value.Y;
- end;
- procedure TForm1.TrackingTimerTimer(Sender: TObject);
- var
- Delay: Cardinal;
- begin
- Delay := GetTickCount - FPrevTick;
- if FDragging then
- begin
- if Delay = 0 then
- Delay := 1;
- FSpeedX := (ScrollPos.X - FPrevScrollPos.X) / Delay;
- FSpeedY := (ScrollPos.Y - FPrevScrollPos.Y) / Delay;
- end
- else
- begin
- if (Abs(FSpeedX) < 0.005) and (Abs(FSpeedY) < 0.005) then
- TrackingTimer.Enabled := False
- else
- begin
- ScrollPos := Point(FPrevScrollPos.X + Round(Delay * FSpeedX),FPrevScrollPos.Y + Round(Delay * FSpeedY));
- FSpeedX := 0.83 * FSpeedX;
- FSpeedY := 0.83 * FSpeedY;
- end;
- end;
- FPrevScrollPos := ScrollPos;
- FPrevTick := GetTickCount;
- end;
- end.
代码(面板):
如果您不想使用滚动条,请使用以下代码.该示例使用面板作为容器,但可以是任何窗口控件或表单本身.
- unit Unit2;
- interface
- uses
- Windows,Math;
- type
- TForm2 = class(TForm)
- Panel: TPanel;
- Image: TImage;
- TrackingTimer: TTimer;
- procedure PanelMouseDown(Sender: TObject; Button: TMouseButton;
- Shift: TShiftState; X,Y: Integer);
- procedure PanelMouseMove(Sender: TObject; Shift: TShiftState; X,Y: Integer);
- procedure PanelMouseUp(Sender: TObject; Button: TMouseButton;
- Shift: TShiftState; X,Y: Integer);
- procedure TrackingTimerTimer(Sender: TObject);
- procedure FormCreate(Sender: TObject);
- private
- FDragging: Boolean;
- FPrevImagePos: TPoint;
- FPrevTick: Cardinal;
- FSpeedX: Single;
- FSpeedY: Single;
- FStartPos: TPoint;
- function GetImagePos: TPoint;
- procedure SetImagePos(Value: TPoint);
- public
- property ImagePos: TPoint read GetImagePos write SetImagePos;
- end;
- implementation
- {$R *.dfm}
- procedure TForm2.FormCreate(Sender: TObject);
- begin
- Panel.DoubleBuffered := True;
- end;
- function TForm2.GetImagePos: TPoint;
- begin
- Result.X := Image.Left;
- Result.Y := Image.Top;
- end;
- procedure TForm2.PanelMouseDown(Sender: TObject; Button: TMouseButton;
- Shift: TShiftState; X,Y: Integer);
- begin
- FDragging := True;
- FPrevTick := GetTickCount;
- FPrevImagePos := ImagePos;
- TrackingTimer.Enabled := True;
- FStartPos := Point(X - Image.Left,Y - Image.Top);
- Screen.Cursor := crHandPoint;
- end;
- procedure TForm2.PanelMouseMove(Sender: TObject; Shift: TShiftState; X,Y: Integer);
- begin
- if FDragging then
- ImagePos := Point(X - FStartPos.X,Y - FStartPos.Y);
- end;
- procedure TForm2.PanelMouseUp(Sender: TObject; Button: TMouseButton;
- Shift: TShiftState; X,Y: Integer);
- begin
- FDragging := False;
- Screen.Cursor := crDefault;
- end;
- procedure TForm2.SetImagePos(Value: TPoint);
- begin
- Value.X := Max(Panel.ClientWidth - Image.Width,Min(0,Value.X));
- Value.Y := Max(Panel.ClientHeight - Image.Height,Value.Y));
- Image.SetBounds(Value.X,Value.Y,Image.Width,Image.Height);
- end;
- procedure TForm2.TrackingTimerTimer(Sender: TObject);
- var
- Delay: Cardinal;
- begin
- Delay := GetTickCount - FPrevTick;
- if FDragging then
- begin
- if Delay = 0 then
- Delay := 1;
- FSpeedX := (ImagePos.X - FPrevImagePos.X) / Delay;
- FSpeedY := (ImagePos.Y - FPrevImagePos.Y) / Delay;
- end
- else
- begin
- if (Abs(FSpeedX) < 0.005) and (Abs(FSpeedY) < 0.005) then
- TrackingTimer.Enabled := False
- else
- begin
- ImagePos := Point(FPrevImagePos.X + Round(Delay * FSpeedX),FPrevImagePos.Y + Round(Delay * FSpeedY));
- FSpeedX := 0.83 * FSpeedX;
- FSpeedY := 0.83 * FSpeedY;
- end;
- end;
- FPrevImagePos := ImagePos;
- FPrevTick := GetTickCount;
- end;
- end.
代码(用于绘图框):
当图像的尺寸是无限的(例如地球仪)时,您可以使用油漆盒将图像的端部粘合在一起.
- unit Unit3;
- interface
- uses
- Windows,Graphics,JPEG;
- type
- TForm3 = class(TForm)
- Painter: TPaintBox;
- Tracker: TTimer;
- procedure FormCreate(Sender: TObject);
- procedure FormDestroy(Sender: TObject);
- procedure PainterMouseDown(Sender: TObject; Button: TMouseButton;
- Shift: TShiftState; X,Y: Integer);
- procedure PainterMouseMove(Sender: TObject; Shift: TShiftState; X,Y: Integer);
- procedure PainterMouseUp(Sender: TObject; Button: TMouseButton;
- Shift: TShiftState; X,Y: Integer);
- procedure PainterPaint(Sender: TObject);
- procedure TrackerTimer(Sender: TObject);
- private
- FDragging: Boolean;
- FGraphic: TGraphic;
- FOffset: Integer;
- FPrevOffset: Integer;
- FPrevTick: Cardinal;
- FSpeed: Single;
- FStart: Integer;
- procedure SetOffset(Value: Integer);
- public
- property Offset: Integer read FOffset write SetOffset;
- end;
- implementation
- {$R *.dfm}
- procedure TForm3.FormCreate(Sender: TObject);
- begin
- DoubleBuffered := True;
- FGraphic := TJPEGImage.Create;
- FGraphic.LoadFromFile('gda_world_map_small.jpg');
- Constraints.MaxWidth := FGraphic.Width + 30;
- end;
- procedure TForm3.FormDestroy(Sender: TObject);
- begin
- FGraphic.Free;
- end;
- procedure TForm3.PainterMouseDown(Sender: TObject; Button: TMouseButton;
- Shift: TShiftState; X,Y: Integer);
- begin
- FDragging := True;
- FPrevTick := GetTickCount;
- FPrevOffset := Offset;
- Tracker.Enabled := True;
- FStart := X - FOffset;
- Screen.Cursor := crHandPoint;
- end;
- procedure TForm3.PainterMouseMove(Sender: TObject; Shift: TShiftState; X,Y: Integer);
- begin
- if FDragging then
- Offset := X - FStart;
- end;
- procedure TForm3.PainterMouseUp(Sender: TObject; Button: TMouseButton;
- Shift: TShiftState; X,Y: Integer);
- begin
- FDragging := False;
- Screen.Cursor := crDefault;
- end;
- procedure TForm3.PainterPaint(Sender: TObject);
- begin
- Painter.Canvas.Draw(FOffset,FGraphic);
- Painter.Canvas.Draw(FOffset + FGraphic.Width,FGraphic);
- end;
- procedure TForm3.SetOffset(Value: Integer);
- begin
- FOffset := Value;
- if FOffset < -FGraphic.Width then
- begin
- Inc(FOffset,FGraphic.Width);
- Dec(FStart,FGraphic.Width);
- end
- else if FOffset > 0 then
- begin
- Dec(FOffset,FGraphic.Width);
- Inc(FStart,FGraphic.Width);
- end;
- Painter.Invalidate;
- end;
- procedure TForm3.TrackerTimer(Sender: TObject);
- var
- Delay: Cardinal;
- begin
- Delay := GetTickCount - FPrevTick;
- if FDragging then
- begin
- if Delay = 0 then
- Delay := 1;
- FSpeed := (Offset - FPrevOffset) / Delay;
- end
- else
- begin
- if Abs(FSpeed) < 0.005 then
- Tracker.Enabled := False
- else
- begin
- Offset := FPrevOffset + Round(Delay * FSpeed);
- FSpeed := 0.83 * FSpeed;
- end;
- end;
- FPrevOffset := Offset;
- FPrevTick := GetTickCount;
- end;
- end.