- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在使用 TImage
控件制作一个基于 TScrollingWinControl
(以及从 TScrollBox
复制的代码)的简单控件。我在某种程度上可以进行缩放,但它不一定会缩放到焦点 - 滚动条不会相应地改变以保持中心点处于焦点。
我希望能够告诉这个控件 ZoomTo(const X, Y, ZoomBy: Integer);
告诉它将焦点缩放到哪里。因此,当它缩放时,我传递的坐标将保持“居中”。同时,我还需要一个 ZoomBy(const ZoomBy: Integer);
告诉它保持在当前 View 的中心。
例如,有一种情况,鼠标指向图像的特定点,当按住 control 并向上滚动鼠标时,它应该放大并聚焦于鼠标指针。另一方面,另一种情况是滑动控件来调整缩放级别,在这种情况下,它只需要保持当前 View 的中心(不一定是图像的中心)聚焦。
问题是我的数学在这一点上迷失了,我无法找出调整这些滚动条的正确公式。我尝试了几种不同的计算方法,但似乎都不起作用。
这是我的控件的精简版本。我删除了大部分内容,仅保留相关内容,原始单元有 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.
最佳答案
在传递给“ZoomBy()”时,尚不清楚您希望为 X、Y 引用什么。我假设您已经为图像放置了一个“OnMouseDown”处理程序,并且坐标指的是您单击图像的位置,即它们与滚动框坐标无关。如果不是这样,您可以自行调整。
让我们暂时忘记缩放,让我们的任务集中在滚动框中单击图像的点上。很简单,我们知道滚动框的中心位于 (ScrollBox.ClientWidth/2, ScrollBox.ClientHeight/2)。考虑水平方向,我们想要向上滚动到一个点,这样,如果我们将 ClientWidth/2 添加到其中,它将成为我们的点击点:
procedure ScrollTo(CenterX, CenterY: Integer);
begin
ScrollBox.HorzScrollBar.Position := CenterX - Round(ScrollBox.ClientWidth / 2);
ScrollBox.VertScrollBar.Position := CenterY - Round(ScrollBox.ClientHeight / 2);
end;
现在考虑缩放。我们要做的就是相应地计算X、Y位置,滚动框的大小不会改变。 CenterX := Center.X * ZoomFactor
。但要注意,这里的“ZoomFactor”不是有效缩放,而是当我们点击图像时将应用的缩放。我将使用图像的前后尺寸来确定:
procedure ZoomTo(CenterX, CenterY, ZoomBy: Integer);
var
OldWidth, OldHeight: Integer;
begin
OldWidth := FImage.Width;
OldHeight := FImage.Height;
// zoom the image, we have new image size and scroll range
CenterX := Round(CenterX * FImage.Width / OldWidth);
ScrollBox.HorzScrollBar.Position := CenterX - Round(ScrollBox.ClientWidth / 2);
CenterY := Round(CenterY * FImage.Height / OldHeight);
ScrollBox.VertScrollBar.Position := CenterY - Round(ScrollBox.ClientHeight / 2);
end;
当然,您可以将它们重构为一行,以便仅调用 Round() 一次以减少舍入误差。
我相信您可以自己在这里锻炼。
关于delphi - 放大/缩小 TScrollBox 内的 TImage 到特定焦点?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10406584/
我正在为我的学校项目在 Lazarus 写 2-3 Trees 应用程序。 一切都完成了,现在开始玩 GUI(我得到的好 GUI 的分数与我得到的好等的分数相同。插入功能,这很奇怪,但 nvm)。 当
当创建一个新的 TImage 时,它是透明的。将对象绘制到该图像后,我想清除它们。请注意,我需要保持图像透明,因为 TImage 被用作另一个图像的叠加层。 TImage 的某种“清晰”功能是最好
我正在尝试制作一个如下所示的裁剪工具: 原始图片: 裁剪工具 - 这就是我想要的: 请注意,裁剪区域显示的是原始颜色,而周围的颜色较暗。 我所做的就是在我的 TImage 上放置一个 TShape ,
我已经按照这个答案来裁剪图像: how do I crop a bitmap “in place”? 在delphi 7中我有一个TImage Image_center。 Image := TPngO
我在面板上布置了一组 TImage 实例。 TImages 代表图标(见附件截图)。当用户通过单击选择它时,我想在给定的 TImage 实例周围绘制一个红色矩形。不确定如何进行... 编辑:为什么我不
我在 Firemonkey 中有一个 TImage 控件(不是 TImageControl)。该控件内的位图居中且不占据整个 TImage。如何获取位图的坐标(左和上)? 最佳答案 与@GolezTr
我有一个显示图片的 Delphi TImage 组件。有时图片比图像尺寸大,需要滚动。我不想使用拉伸(stretch)属性和自动调整大小属性,我想通过滚动来查看图片。我怎样才能做到这一点?我可以使用
我有 TImage 800x600 和图像 1024x768。 TImage 与 alClient 对齐。 Timage 是成比例的。 TImage 被拉伸(stretch)。 当我调整表单大小时,图
我正在使用以下过程来识别 Delphi XE3 中鼠标下的控件。对于 vcl.contols 来说,一切都运行良好。但是,当鼠标悬停在 TImage 上时,不会返回控件名称。 procedure TM
如何在 Delphi 中平铺 TImage 中的图像? 为什么我需要它:我可以创建一个并将图像存储在那里,而不是在运行时创建更多 TImage,因为我知道它将“适合”直到达到 TImage 的高度和宽
这是我的整个代码: unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics,
对于新手问题,我提前表示歉意,但为什么下面的代码(在“Create(SelectorForm);”行上)会出现“访问冲突”错误?我尝试使用主窗体作为所有者,但没有任何区别。 var Selecto
看下面的图片: 如您所见,我无法将按钮发送到后面。这仅适用于标签。 那么我怎样才能将TImage发送到前面并具有透明度。 顺便说一句,我读过 This related question但没有帮助我。因
编写移动应用程序 - 它从安全网站提取图像,如下所示(第一个图像)提取不正确(注意网络版本与移动版本),第二个图像在网站上正确显示,但 Delphi TImage 正在旋转它由于某种原因,我不明白为什
我有一些图像文件存储在一个文件中(某种存档)。该文件如下所示: 嗯,它分为两个段 - header 和数据段。标题(绿色)包含各种信息,例如相册名称、位置、日期/时间、描述、相册中的照片数量等。数据段
我创建了一个图像列表,其中包含 20 个位图,下拉列表值从 1 到 20。当我选择下拉列表时,它应该显示与下拉列表索引相对应的位图。我面临的问题是,当我选择下拉列表且图像太小时,它一直显示相同的图像。
我对 delphi 很陌生,正在为我的 A level 做一个项目。当我运行我的代码时,图像不显示,我到处都看了,但我的老师无法帮助我。谁能告诉我我错过了什么? const An
This tutorial表示为了将效果应用于图像,您需要将该效果设为该图像的 MultiResBitmap 的子级: 我做不到。该效果拒绝嵌套在 MultiResBitmap 下。它仍然停留在 Im
我想将 TButton 或 TSpeedButton 放在 TImage 之上并使按钮透明,以便您仍然可以单击它,但您看到的是图像而不是按钮。我似乎无法让它工作,我将 TSpeedButton 更改为
我正在构建一个编辑器,它使用 TImage 来显示图片,并具有鼠标事件来能够在图像上绘制、移动框和调整框大小。这一切都很完美。现在我正在尝试实现使用键盘上的箭头移动选定框的功能,但是A)TImage没
我是一名优秀的程序员,十分优秀!