Delphi XE2 Firemonkey 的 Align 属性设置为 alScale 对坐标系有何影响?

Posted

技术标签:

【中文标题】Delphi XE2 Firemonkey 的 Align 属性设置为 alScale 对坐标系有何影响?【英文标题】:How does Delphi XE2 Firemonkey's Align property set to alScale affect the coordinate system? 【发布时间】:2012-08-26 20:58:40 【问题描述】:

我正在查看 Firemonkey 的画布绘图功能,并在组件的 Align 属性设置为 alScale 时遇到了坐标系统问题。以下演示程序(FM HD 应用程序)说明了该问题。 编译并运行示例代码,画几行,然后更改表单的大小以开始奇怪。这些线条没有出现在预期的位置。

任何建议和解释将不胜感激!提前致谢。

主窗体(LineDrawFormUnit.pas):

unit LineDrawFormUnit;

interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
  FMX.Types, FMX.Controls, FMX.Forms, FMX.Dialogs, FMX.Objects;

type
  TLineDrawForm = class(TForm)
    Image1: TImageControl;
    Panel1: TPanel;
    Label1: TLabel;
    Label2: TLabel;
    lX: TLabel;
    lY: TLabel;
     These event handlers are set in the IDE's object inspector 
    procedure Image1MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Single);
    procedure Image1MouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Single);

     This event handler is set/unset with the MouseDown and MouseUp events to capture mouse moves when drawing 
    procedure ImageControl1MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Single);
    procedure FormCreate(Sender: TObject);

  private
    FSaveBitmap: TBitmap;
    p1, p2: TPointF;     Start and end points of lines to draw 
  end;

var
  LineDrawForm: TLineDrawForm;

implementation
$R *.fmx

procedure TLineDrawForm.FormCreate(Sender: TObject);
begin
  Image1.Bitmap.Create(Round(Image1.Width), Round(Image1.Height));
end;

procedure TLineDrawForm.Image1MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X,
  Y: Single);
begin
  p1.X := X;
  p1.Y := Y;
  lX.Text := FloatToStr(X);
  lY.Text := FloatToStr(Y);
  FSaveBitmap := TBitmap.Create(Image1.Bitmap.Width, Image1.Bitmap.Height);
  FSaveBitmap.Assign(Image1.Bitmap);  Save the current canvas as bitmap 
  Image1.OnMouseMove := ImageControl1MouseMove;  Activate the MouseMove event handler
end;

procedure TLineDrawForm.ImageControl1MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Single);
begin
  p2.X := X;
  p2.Y := Y;
  lX.Text := FloatToStr(X);
  lY.Text := FloatToStr(Y);
  Image1.Bitmap.Assign(FSaveBitmap);
  Image1.Bitmap.Canvas.BeginScene;
  try
    Image1.Bitmap.Canvas.Stroke.Color := claGray;
    Image1.Bitmap.Canvas.StrokeThickness := 0.5;
    Image1.Bitmap.Canvas.DrawLine(p1, p2, 1.0);
  finally
    Image1.Bitmap.Canvas.EndScene;
    Image1.Bitmap.BitmapChanged;
  end;
end;

procedure TLineDrawForm.Image1MouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X,
  Y: Single);
begin
  p2.X := X;
  p2.Y := Y;
  lX.Text := FloatToStr(X);
  lY.Text := FloatToStr(Y);
  Image1.Bitmap.Canvas.BeginScene;
  try
    Image1.Bitmap.Canvas.Stroke.Color := claBlack;
    Image1.Bitmap.Canvas.StrokeThickness := 2;
    Image1.Bitmap.Canvas.DrawLine(P1, P2, 1.0);
  finally
    Image1.Bitmap.Canvas.EndScene;
    Image1.Bitmap.BitmapChanged;
  end;

  (Sender as TControl).OnMouseMove := nil;
  if FSaveBitmap <> nil then
    FSaveBitmap.Free;

end;

end.

FMX 文件(LineDrawFormUnit.fmx):

object LineDrawForm: TLineDrawForm
  Left = 0
  Top = 0
  Caption = 'Polygon Form'
  ClientHeight = 513
  ClientWidth = 650
  Visible = False
  OnCreate = FormCreate
  StyleLookup = 'backgroundstyle'
  object Image1: TImageControl
    Align = alScale
    Position.Point = '(18,21)'
    Width = 620.000000000000000000
    Height = 452.000000000000000000
    OnMouseDown = Image1MouseDown
    OnMouseUp = Image1MouseUp
    TabOrder = 0
  end
  object Panel1: TPanel
    Align = alBottom
    Position.Point = '(0,480)'
    Width = 650.000000000000000000
    Height = 33.000000000000000000
    TabOrder = 2
    object Label1: TLabel
      Position.Point = '(16,8)'
      Width = 25.000000000000000000
      Height = 15.000000000000000000
      TabOrder = 1
      Text = 'X:'
    end
    object Label2: TLabel
      Position.Point = '(384,8)'
      Width = 25.000000000000000000
      Height = 15.000000000000000000
      TabOrder = 2
      Text = 'Y:'
    end
    object lX: TLabel
      Position.Point = '(32,8)'
      Width = 313.000000000000000000
      Height = 15.000000000000000000
      TabOrder = 3
      Text = '0'
    end
    object lY: TLabel
      Position.Point = '(424,8)'
      Width = 209.000000000000000000
      Height = 15.000000000000000000
      TabOrder = 4
      Text = '0'
    end
  end
end

【问题讨论】:

P.S.我最初忘记在接口 Uses 子句中删除未使用的 PolygonUnit,现在已更正。 Image1.Bitmap 随表格放大时,Image1.Bitmap 未按比例放大。但是,当 Image1 与窗体一起缩小时,它的大小会减小,而当窗体展开时,它会再次扩大到原始大小。为表单设置 OnResize 处理程序允许调整 Image1.Bitmap 的大小以匹配其容器,但它被清除。当窗体的大小缩小和扩大时,位图会缩小并恢复到其原始大小。必须有一种无损方式来调整 TBitmap 的大小而不清除其内容。否则,将不得不求助于使用 TBitmap.ScanLine 函数。 P.S.放大位图会使它变得粗糙,因此位图缩小并返回到其原始大小而不是更大是有意义的。还需要弄清楚框架内部是如何实现的。 我认为这与Align 属性没有任何关系(顺便说一下,它也可以与alClient 重现)。问题是由于图像控件的大小已调整但其位图未调整,因此它会缩放。创建 FSaveBitmap 时,您应该使用图像控件的大小创建它,而不是其内部位图(否则您不会反映控件的更改大小并导致缩放)。 谢谢 TOndrej。我会试试你的建议。 【参考方案1】:

align 属性影响 TShapes 后代、TControl 等,但不影响位图的内容。

您似乎在 TBitmap 上缓冲了一些自定义绘图,然后将其分配给控件。 FMX 将无法重新对齐自定义图形,因为它们没有封装在可对齐的类中(只是一些像素)。

您可以在调整控件大小时重新绘制“缓冲区”并将其重新分配给其“主机”以根据您的意愿调整绘图。或者也许不要释放“缓冲图纸”并在调整表单大小时对其进行转换/重新分配。

但是,一种更好的方法是使用形状系统,它与 FMX HD 的预期使用方式相匹配,对齐将是自动的。 所以不要画线,而是在父对象内部创建一个 TLine 并根据父控件分层这条新线的对齐方式。

【讨论】:

感谢您的回复。我现在正在使用使用 TPath 对象的类似方法。它让生活变得更加轻松。此外,MouseDown 事件已经非常有效地检查多边形中的点。为我找到的路径对象创建数据的最简单方法是在 Illustrator/InkScape 中绘制形状,以 SVG 格式保存文件并使用文本编辑器从文件中提取相关路径信息。我真的希望 FireMonkey 有更好的文档。

以上是关于Delphi XE2 Firemonkey 的 Align 属性设置为 alScale 对坐标系有何影响?的主要内容,如果未能解决你的问题,请参考以下文章

如何在Delphi FireMonkey中发送iOS的推送通知

Delphi xe7 FireMonkey / Mobile (Android, iOS)生成 QR Code完整实例

怎么设置禁止delphi Xe2 自动检查更新

如何改变delphi xe2编程环境下所显示的源代码的字体大小

在 Delphi XE2 中使用泛型和前向声明时的编译器错误

Delphi XE2:跳到 CHM 中的锚点?