我正在玩FireMonkey只是为了测试一些东西。其中一个是在画布上实现“非常简单”的绘图。例如Line,Rectangle等......
第一个问题是,是否有相当于为VCL for FireMonkey提供的graphex演示?
否则,出于练习的目的,我正在尝试在FireMonkey中复制该演示,而刚才是线条图。我可以让线条图像工作,就像我在线条周围移动鼠标时所预期的那样。不幸的是,我不能让它自动擦除在鼠标所在的前一点绘制的旧行。这似乎是由TPen属性的TPenMode属性处理的 - 我可以告诉它 - 在FireMonkey中的TStroke属性。即在绘制(移动鼠标)时将属性设置为pmXor,然后在完成时将其设置为pmCopy。
我如何使用FireMonkey做类似的事情?
这是在TImage的MouseMove事件期间调用的例程:
FDrawSurface.Bitmap.Canvas.BeginScene;
try
case FShapeToDraw of
doLine:
begin
FDrawSurface.Bitmap.Canvas.DrawLine(PointF(TopLeft.X, TopLeft.Y), PointF(BottomRight.X, BottomRight.Y), 100);
end;
end;
finally
FDrawSurface.Bitmap.Canvas.EndScene;
FDrawSurface.Bitmap.BitmapChanged;
end;
FDrawSurface是一个TImage。 TopLeft是一个TPoint,它包含鼠标在TImaeg的OnMouseDown事件中捕获的位置的X和Y,而BottomRight是来自OnMouseMove事件的当前X和Y坐标。
因此每次移动鼠标时,我的图像上都会出现“附加”行。
由于
答案 0 :(得分:4)
AFAIK,FMX没有这样的模式...... 此外,您在画布上绘制的内容并未真正保存(如果您知道如何直接保存它,请在评论中解释我):如果您将表单移到桌面之外,然后将其恢复,则清理画布...
因此,要实现graphex演示,您必须使用其他技术进行编码..
例如,使用TBitmap存储您的真实“图像”,并仅使用画布进行“预览”......
unit main;
interface
uses
System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
FMX.Types, FMX.Controls, FMX.Forms, FMX.Dialogs, FMX.Objects;
type
TfrmMain = class(TForm)
recBoard: TRectangle;
btnCopy: TButton;
Image1: TImage;
procedure recBoardMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Single);
procedure recBoardMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Single);
procedure recBoardMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Single);
procedure recBoardMouseInOut(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure btnCopyClick(Sender: TObject);
procedure FormDestroy(Sender: TObject);
private
{ Private declarations }
bmp: TBitmap;
pFrom, pTo: TPointF;
public
{ Public declarations }
end;
var
frmMain: TfrmMain;
implementation
{$R *.fmx}
procedure TfrmMain.btnCopyClick(Sender: TObject);
begin
Image1.Bitmap.Assign(bmp);
end;
procedure TfrmMain.FormCreate(Sender: TObject);
begin
pFrom := PointF(-1, -1);
bmp := TBitmap.Create(Round(recBoard.Width), Round(recBoard.Height));
end;
procedure TfrmMain.FormDestroy(Sender: TObject);
begin
bmp.Free;
end;
procedure TfrmMain.recBoardMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Single);
begin
if Button = TMouseButton.mbLeft then
begin
pFrom := PointF(X, Y);
pTo := PointF(X, Y);
end;
end;
procedure TfrmMain.recBoardMouseInOut(Sender: TObject);
begin
pFrom := PointF(-1, -1);
end;
procedure TfrmMain.recBoardMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Single);
begin
if ((pFrom.X <> -1) and (pFrom.X <> -1)) then
with recBoard.Canvas do
begin
BeginScene;
if ssLeft in Shift then
begin
FillRect(RectF(0, 0, bmp.Width, bmp.Height), 0, 0, [], 255);
DrawBitmap(bmp, RectF(0, 0, bmp.Width, bmp.Height), RectF(0, 0, bmp.Width, bmp.Height), 255);
Stroke.Color := claBlue;
pTo := PointF(X, Y);
DrawEllipse(RectF(pFrom.X, pFrom.Y, pTo.X, pTo.Y), 255);
end;
EndScene;
end;
Self.Caption := Format('(%0.0f;%0.0f)', [X, Y]);
end;
procedure TfrmMain.recBoardMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Single);
begin
with bmp.Canvas do
begin
BeginScene;
DrawEllipse(RectF(pFrom.X, pFrom.Y, pTo.X, pTo.Y), 255);
EndScene;
end;
pFrom := PointF(-1, -1);
end;
end.
答案 1 :(得分:2)
我最终做的 - 基于上面的Whiler的洞察力,是在“绘制例程”(即鼠标按下)开始时存储位图的状态,然后在MouseMove上存储,然后我渲染新线(在此例如),我恢复状态,然后绘制新线......
procedure TFMXDrawSurface.DrawSurfaceMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Single);
begin
FOrigin := PointF(X, Y);
FMovePt := PointF(X, Y);
FPrevPt := PointF(X, Y);
FDrawing := True;
FTempDrawbitmap.Assign(FDrawSurface.Bitmap);
end;
procedure TFMXDrawSurface.DrawSurfaceMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Single);
begin
if FDrawing then
begin
DrawShape(FOrigin, FMovePt);
FMovePt := PointF(X, Y);
DrawShape(FOrigin, FMovePt);
FPrevPt := PointF(X, Y);
end;
end;
procedure TFMXDrawSurface.DrawShape(TopLeft, BottomRight: TPointF);
var
R: TRectF;
begin
FDrawSurface.Bitmap.Canvas.BeginScene;
try
case FShapeToDraw of
doLine:
begin
// restore canvas to initial state so we don't keep old movement data around
R.TopLeft := PointF(0.0, 0.0);
R.BottomRight := PointF(FDrawSurface.Width, FDrawSurface.Height);
FDrawSurface.Bitmap.Canvas.DrawBitmap(FTempDrawBitmap, R, R, 100);
FDrawSurface.Bitmap.Canvas.RestoreState(FDrawState);
FDrawSurface.Bitmap.Canvas.DrawLine(PointF(TopLeft.X, TopLeft.Y), PointF(BottomRight.X, BottomRight.Y), 100);
end;
end;
finally
FDrawSurface.Bitmap.Canvas.EndScene;
FDrawSurface.Bitmap.BitmapChanged;
end;
end;
它有效,但我不知道它是否是“正确”的方式......