(ve TScrollBox
'dan kopyalanan kod) TImage
denetimi ile basit bir denetim yapıyorum. Çalışmak için biraz zum yaptım, ancak odaklanmış bir noktaya zıt bir görüntü oluşturmuyor - kaydırma noktası merkez noktasını odakta tutmak için buna göre değişmiyor.Belirli bir odağa TScrollBox içinde bir TImage in/in yakınlaştırma mı?
Bu denetimi ZoomTo(const X, Y, ZoomBy: Integer);
anlatıp odağı yakınlaştırmak istediğinizi söyleyebilmeyi isterim. Bu yüzden, yakınlaştırdığımda, geçtiğim koordinatlar “ortalanmış” kalacaktır. Aynı zamanda, mevcut görünümde ortalamasını tutmasını söyleyen ZoomBy(const ZoomBy: Integer);
'a da ihtiyacım var. Örneğin, farenin görüntünün belirli bir noktasında işaret edildiği tek bir senaryo olacak ve denetimi tutarken ve fareyi yukarı kaydırırken, fare imlecine odaklanmalı zum yapmalıdır. Diğer yandan, bir başka senaryo, yakınlaştırma seviyesini ayarlamak için bir kontrol kayarken, bu durumda sadece mevcut görüntünün merkezini (görüntünün merkezi değil) odaklanmış olması gerekir.
Sorun şu ki, matematik bu noktada kayboluyor ve bu kaydırma çubuklarını ayarlamak için doğru formülü anlayamıyorum. Birkaç farklı hesaplama yöntemi denedim, hiçbir şey doğru çalışmıyor gibi görünüyor.
Kontrolümün soyulmuş bir sürümü. En çok ilgili şeyleri kaldırdım, orijinal birim 600'den fazla kod satırı. En önemli prosedür aşağıda 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.
"Yakınlaştır" noktasının ne yapacağını hayal bile edemiyorum bile. Bir dikdörtgeni "yakınlaştırır", bir noktaya değil. Sınıfının uygulanmasının neye benzediğini tahmin edemem, o yüzden hangi matematiğe ihtiyacın olduğunu, başka kimseyi de tahmin edemiyorum. –
@WarrenP Birden çok kişinin fotoğrafını görüntülediğini farz edelim, fare bir kişinin yüzüne işaret ediyor. Kullanıcı kontrol tuşunu basılı tuttuğunda ve fare tekerleğini yukarı kaydırdığında, fare imlecinin hala resmin aynı pozisyonunda olduğu o kişinin yüzüne zum yapar. İşte bu yüzden bir “Nokta” ya da “Rect” e değil. Fare olaylarını nasıl ele aldığımı göstermek için yukarıdaki ilgili tüm kodu eklediğime eminim. –