TScrollingWinControl
コントロールを使用して、 (およびからコピーされたコードTScrollBox
)に基づいて単純なコントロールを作成していTImage
ます。ズームが機能するようになりましたが、必ずしも焦点が合っているとは限りません。スクロールバーは、中心点に焦点を合わせ続けるためにそれに応じて変化しません。
ZoomTo(const X, Y, ZoomBy: Integer);
このコントロールに、フォーカスをどこにズームするかを指示できるようにしたいと思います。したがって、ズームすると、渡した座標は「中心」のままになります。同時に、ZoomBy(const ZoomBy: Integer);
現在のビューの中央に保持するように指示する も必要です。
たとえば、マウスが画像の特定のポイントを指しているシナリオが 1 つあります。コントロールを押したままマウスを上にスクロールすると、マウス ポインターにフォーカスしてズームインする必要があります。一方、別のシナリオでは、コントロールをスライドさせてズーム レベルを調整します。この場合、現在のビューの中心 (必ずしも画像の中心である必要はありません) を維持する必要があります。
問題は、この時点で数学が失われてしまい、これらのスクロール バーを調整するための正しい数式を理解できないことです。私はいくつかの異なる計算方法を試しましたが、何も正しく機能していないようです。
これが私のコントロールの削除されたバージョンです。関連するものだけを削除しました。元のユニットは 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.