我正在做TScrollingWinControl
(和從TScrollBox
複製的代碼)與TImage
控制基於簡單的控制。我有些縮放工作,但它不一定縮小到一個焦點 - 滾動條不會相應地改變,以保持中心點的焦點。將TScrollBox中的TImage放大/縮小到特定焦點?
我希望能夠告訴這個控制ZoomTo(const X, Y, ZoomBy: Integer);
告訴它的焦點縮放。所以當它放大時,我通過的座標將保持「居中」。同時,我還需要有一個ZoomBy(const ZoomBy: Integer);
,它告訴它保持它在當前視圖中居中。
例如,將有一個場景,其中鼠標指向在圖像的特定點,並保持控制和滾動鼠標向上時,應該在聚焦在鼠標指針放大。另一方面,另一種情況是滑動控件來調整縮放級別,在這種情況下,它只需要保持當前視圖的中心(不一定是圖像的中心)。
問題是我的數學丟失在這一點上,我想不出合適的辦法來調整這些滾動條。我嘗試了幾種不同的計算方法,似乎沒有什麼工作正確。
這裏是我的控件的剝離版本。我刪除了最多隻有相關的東西,原單位是超過600行代碼。下面最重要的程序是SetZoom(const Value: Integer);
unit JD.Imaging;
interface
uses
Windows, Classes, SysUtils, Graphics, Jpeg, PngImage, Controls, Forms,
ExtCtrls, Messages;
type
TJDImageBox = class;
TJDImageZoomEvent = procedure(Sender: TObject; const Zoom: Integer) of object;
TJDImageBox = class(TScrollingWinControl)
private
FZoom: Integer; //level of zoom by percentage
FPicture: TImage; //displays image within scroll box
FOnZoom: TJDImageZoomEvent; //called when zoom occurs
FZoomBy: Integer; //amount to zoom by (in pixels)
procedure MouseWheel(Sender: TObject; Shift: TShiftState;
WheelDelta: Integer; MousePos: TPoint; var Handled: Boolean);
procedure SetZoom(const Value: Integer);
procedure SetZoomBy(const Value: Integer);
public
constructor Create(AOwner: TComponent); override;
published
property Zoom: Integer read FZoom write SetZoom;
property ZoomBy: Integer read FZoomBy write SetZoomBy;
property OnZoom: TJDImageZoomEvent read FOnZoom write FOnZoom;
end;
implementation
{ TJDImageBox }
constructor TJDImageBox.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
OnMouseWheel:= MouseWheel;
ControlStyle := [csAcceptsControls, csCaptureMouse, csClickEvents,
csSetCaption, csDoubleClicks, csPannable, csGestures];
AutoScroll := True;
TabStop:= True;
VertScrollBar.Tracking:= True;
HorzScrollBar.Tracking:= True;
Width:= 100;
Height:= 100;
FPicture:= TImage.Create(nil);
FPicture.Parent:= Self;
FPicture.AutoSize:= False;
FPicture.Stretch:= True;
FPicture.Proportional:= True;
FPicture.Left:= 0;
FPicture.Top:= 0;
FPicture.Width:= 1;
FPicture.Height:= 1;
FPicture.Visible:= False;
FZoom:= 100;
FZoomBy:= 10;
end;
destructor TJDImageBox.Destroy;
begin
FImage.Free;
FPicture.Free;
inherited;
end;
procedure TJDImageBox.MouseWheel(Sender: TObject; Shift: TShiftState;
WheelDelta: Integer; MousePos: TPoint; var Handled: Boolean);
var
NewScrollPos: Integer;
begin
if ssCtrl in Shift then begin
if WheelDelta > 0 then
NewScrollPos := Zoom + 5
else
NewScrollPos:= Zoom - 5;
if NewScrollPos >= 5 then
Zoom:= NewScrollPos;
end else
if ssShift in Shift then begin
NewScrollPos := HorzScrollBar.Position - WheelDelta;
HorzScrollBar.Position := NewScrollPos;
end else begin
NewScrollPos := VertScrollBar.Position - WheelDelta;
VertScrollBar.Position := NewScrollPos;
end;
Handled := True;
end;
procedure TJDImageBox.SetZoom(const Value: Integer);
var
Perc: Single;
begin
FZoom := Value;
if FZoom < FZoomBy then
FZoom:= FZoomBy;
Perc:= FZoom/100;
//Resize picture to new zoom level
FPicture.Width:= Trunc(FImage.Width * Perc);
FPicture.Height:= Trunc(FImage.Height * Perc);
//Move scroll bars to properly position the center of the view
//This is where I don't know how to calculate the 'center'
//or by how much I need to move the scroll bars.
HorzScrollBar.Position:= HorzScrollBar.Position - (FZoomBy div 2);
VertScrollBar.Position:= VertScrollBar.Position - (FZoomBy div 2);
if assigned(FOnZoom) then
FOnZoom(Self, FZoom);
end;
procedure TJDImageBox.SetZoomBy(const Value: Integer);
begin
if FZoomBy <> Value then begin
FZoomBy := EnsureRange(Value, 1, 100);
Paint;
end;
end;
end.
我甚至無法想象「縮放到」點會做什麼。我會「縮放」到一個矩形,而不是一個點。我無法猜測你的班級的實施情況,因此我無法猜測你需要什麼數學,也沒有其他人。 –
@WarrenP假設顯示了多人的照片,鼠標指向了人臉的中心。當用戶拿着控制鍵並向上滾動鼠標滾輪時,它將放大到該人的臉部,鼠標指針仍處於圖片的相同位置。這就是爲什麼我要縮放到一個「Point」而不是「Rect」。我敢肯定,我在上面列出了所有相關代碼,以演示如何處理鼠標事件。 –