Tôi đang thực hiện một điều khiển đơn giản dựa trên số TScrollingWinControl
(và mã được sao chép từ TScrollBox
) với điều khiển TImage
. Tôi phần nào có zooming để làm việc, nhưng nó không nhất thiết phải zoom đến một điểm tập trung - các thanh cuộn không thay đổi cho phù hợp để giữ cho tâm điểm tập trung.Phóng to/thu nhỏ một TImage bên trong TScrollBox đến một tiêu điểm cụ thể?
Tôi muốn có thể cho biết điều khiển này ZoomTo(const X, Y, ZoomBy: Integer);
để cho biết nơi cần phóng to tiêu điểm. Vì vậy, khi nó phóng to, các tọa độ tôi đã vượt qua sẽ ở lại 'trung tâm'. Đồng thời, tôi cũng cần có một số ZoomBy(const ZoomBy: Integer);
để cho nó được căn giữa trong chế độ xem hiện tại.
Ví dụ, sẽ có một trường hợp chuột được trỏ vào một điểm cụ thể của hình ảnh và khi giữ điều khiển và cuộn chuột lên, nó sẽ phóng to tập trung vào con trỏ chuột. Mặt khác, một trường hợp khác sẽ trượt điều khiển để điều chỉnh mức thu phóng, trong trường hợp đó, nó chỉ cần giữ tâm của chế độ xem hiện tại (không nhất thiết là tâm của hình ảnh) được lấy nét.
Vấn đề là toán của tôi bị mất vào thời điểm này và tôi không thể tìm ra công thức phù hợp để điều chỉnh các thanh cuộn này. Tôi đã thử một vài cách khác nhau để tính toán, không có gì có vẻ hoạt động đúng.
Đây là phiên bản bị tước quyền kiểm soát của tôi. Tôi đã xóa hầu hết các nội dung có liên quan, đơn vị ban đầu là hơn 600 dòng mã. Quy trình quan trọng nhất bên dưới là 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.
Tôi thậm chí không thể tưởng tượng điểm "phóng to" sẽ làm gì. Tôi sẽ "phóng to" một hình chữ nhật, không phải là một điểm. Tôi không thể đoán được việc thực hiện lớp học của bạn trông như thế nào nên tôi không thể đoán được bạn cần toán học gì, cũng như không ai khác. –
@WarrenP Giả sử ảnh của nhiều người được hiển thị, chuột được trỏ vào giữa khuôn mặt của một người. Khi người dùng giữ phím điều khiển và cuộn con lăn chuột lên, nó sẽ phóng to khuôn mặt của người đó, với con trỏ chuột vẫn ở cùng vị trí của hình ảnh. Đây là lý do tại sao tôi đang phóng to một 'Điểm' và không phải là một 'Rect'. Tôi khá chắc chắn rằng tôi đã bao gồm tất cả các mã có liên quan ở trên để minh họa cách tôi xử lý các sự kiện chuột. –