的
的士
Unregistered / Unconfirmed
GUEST, unregistred user!
我做的一个简单的画图程序,目前实现了线段选定和拖放功能,但线段拖放的时候在画布
中留下一些“垃圾”,请帮忙看看代码哪里错了,我把整个线段类的代码贴出来。
unit FigureClassUnit;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Math, Forms;
Type
TFigure = class
private
FSelected: Boolean; //是否选中该图形
FCanvas: TCanvas; //画布对象,用来画图形
protected
property Canvas: TCanvas read FCanvas;
public
constructor Create(ACanvas: TCanvas); virtual;
function PointInside(APoint: TPoint): Boolean; virtual; abstract;
function PointInSelectBlock(APoint: TPoint): Boolean; virtual; abstract;
function GetResizeCursorFromPoint(APoint: TPoint): TCursor; virtual; abstract;
procedure Paint; virtual; abstract;
procedure Select; virtual; abstract;
procedure Move(offsetX, offsetY: Integer); virtual; abstract;
procedure UnSelect; virtual; abstract;
property Selected: Boolean read FSelected write FSelected;
end;
TLine = class(TFigure)
private
FBeginPoint, FEndPoint: TPoint; //开始和结束位置
FSelectBlock1, FSelectBlock2: TRect; //当选中线段时,线段的两个选择块
procedure SetBeginPoint(Value: TPoint);
procedure SetEndPoint(Value: TPoint);
public
constructor Create(ACanvas: TCanvas); override;
function PointInside(APoint: TPoint): Boolean; override;
function PointInSelectBlock(APoint: TPoint): Boolean; override;
function GetResizeCursorFromPoint(APoint: TPoint): TCursor; override;
procedure Paint; override;
procedure Select; override;
procedure UnSelect; override;
procedure Move(offsetX, offsetY: Integer); override;
procedure SetBeginEndPoint(ABeginPoint, AEndPoint: TPoint);
property BeginPoint: TPoint read FBeginPoint write SetBeginPoint;
property EndPoint: TPoint read FEndPoint write SetEndPoint;
end;
implementation
{ TFigure }
{-------------------- Public --------------------}
constructor TFigure.Create(ACanvas: TCanvas);
begin
FCanvas := ACanvas;
end;
{ TLine }
{-------------------- Public --------------------}
constructor TLine.Create(ACanvas: TCanvas);
begin
inherited;
FBeginPoint := Point(0, 0);
FEndPoint := Point(0, 0);
end;
{ 判断点是否在直线里面 }
function TLine.PointInside(APoint: TPoint): Boolean;
var
iMaxX, iMinX: Integer;
iMaxY, iMinY: Integer;
k, b: Real;
begin
iMaxX := Max(FBeginPoint.X, FEndPoint.X);
iMinX := Min(FBeginPoint.X, FEndPoint.X);
iMaxY := Max(FBeginPoint.Y, FEndPoint.Y);
iMinY := Min(FBeginPoint.Y, FEndPoint.Y);
{ 如果是垂直线,则直接判断 }
if ((iMaxX - iMinX) <= 5) and ((iMaxY - iMinY) > (iMaxX - iMinX)) then
begin
Result := (Abs(APoint.X - iMaxX) <= 5) and (APoint.Y >= iMinY) and (APoint.Y <= iMaxY);
end
else begin
{ 判断公式为:y = k * x + b 斜率:k = (y2 - y1) / (x2 - x1) y轴截距:b = y1 - k * x1 }
k := (FEndPoint.Y - FBeginPoint.Y) / (FEndPoint.X - FBeginPoint.X);
b := FBeginPoint.Y - k * FBeginPoint.X;
Result := (APoint.Y <= trunc(k * APoint.X + b) + 5) and
(APoint.Y >= trunc(k * APoint.X + b) - 5);
if Result then
Result := (APoint.X >= iMinX) and (APoint.X <= iMaxX) and
(APoint.Y >= iMinY) and (APoint.Y <= iMaxY);
end;
end;
{ 判断点坐标是否在线段的选择块里面 }
function TLine.PointInSelectBlock(APoint: TPoint): Boolean;
begin
Result := PtInRect(FSelectBlock1, APoint) or PtInRect(FSelectBlock2, APoint);
end;
{ 根据点坐标在哪个选择块中,得到改变大小的光标类型 }
function TLine.GetResizeCursorFromPoint(APoint: TPoint): TCursor;
begin
Result := Screen.Cursor;
if PointInSelectBlock(APoint) then
begin
//垂直线
if FBeginPoint.X = FEndPoint.X then
Result := crSizeNS
//水平线
else if FBeginPoint.Y = FEndPoint.Y then
Result := crSizeWE
//右下斜线
else if (FBeginPoint.X - FEndPoint.X < 0) and (FBeginPoint.Y - FEndPoint.Y < 0) then
Result := crSizeNWSE
//右上斜线
else if (FBeginPoint.X - FEndPoint.X < 0) and (FBeginPoint.Y - FEndPoint.Y > 0) then
Result := crSizeNESW
//左下斜线
else if (FBeginPoint.X - FEndPoint.X > 0) and (FBeginPoint.Y - FEndPoint.Y < 0) then
Result := crSizeNWSE
//右上斜线
else if (FBeginPoint.X - FEndPoint.X > 0) and (FBeginPoint.Y - FEndPoint.Y > 0) then
Result := crSizeNWSE
end;
end;
{ 画线段 }
procedure TLine.Paint;
var
oldColor: TColor;
begin
oldColor := Canvas.Brush.Color;
if Selected then
Canvas.Brush.Color := clBlack;
Canvas.FillRect(FSelectBlock1);
Canvas.FillRect(FSelectBlock2);
Canvas.Brush.Color := oldColor;
Canvas.Pen.Mode := pmCopy;
Canvas.MoveTo(FBeginPoint.X, FBeginPoint.Y);
Canvas.LineTo(FEndPoint.X, FEndPoint.Y);
end;
{ 选中线段 }
procedure TLine.Select;
begin
Selected := True;
Paint;
end;
{ 不选中线段 }
procedure TLine.UnSelect;
begin
Selected := False;
Paint;
end;
{ 移动 }
procedure TLine.Move(offsetX, offsetY: Integer);
begin
{ 擦除原来的线段 }
Canvas.Pen.Mode := pmNotXor;
Canvas.FillRect(FSelectBlock1);
Canvas.FillRect(FSelectBlock2);
Canvas.MoveTo(FBeginPoint.X, FBeginPoint.Y);
Canvas.LineTo(FEndPoint.X, FEndPoint.Y);
SetBeginEndPoint(Point(FBeginPoint.X + offsetX, FBeginPoint.Y + offsetY),
Point(FEndPoint.X + offsetX, FEndPoint.Y + offsetY));
{ 重画 }
Paint;
end;
{ 设置线段的起始位置和终止位置 }
procedure TLine.SetBeginEndPoint(ABeginPoint, AEndPoint: TPoint);
begin
SetBeginPoint(ABeginPoint);
SetEndPoint(AEndPoint);
end;
{-------------------- Private --------------------}
{ 设置线段的开始位置 }
procedure TLine.SetBeginPoint(Value: TPoint);
begin
if (Value.X <> FBeginPoint.X) or (Value.Y <> FBeginPoint.Y) then
begin
FBeginPoint := Value;
FSelectBlock1 := Rect(FBeginPoint.X - 3, FBeginPoint.Y - 3,
FBeginPoint.X + 4, FBeginPoint.Y + 4);
end;
end;
{ 设置线段的结束位置 }
procedure TLine.SetEndPoint(Value: TPoint);
begin
if (Value.X <> FEndPoint.X) or (Value.Y <> FEndPoint.Y) then
begin
FEndPoint := Value;
FSelectBlock2 := Rect(FEndPoint.X - 3, FEndPoint.Y - 3,
FEndPoint.X + 4, FEndPoint.Y + 4);
end;
end;
end.
中留下一些“垃圾”,请帮忙看看代码哪里错了,我把整个线段类的代码贴出来。
unit FigureClassUnit;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Math, Forms;
Type
TFigure = class
private
FSelected: Boolean; //是否选中该图形
FCanvas: TCanvas; //画布对象,用来画图形
protected
property Canvas: TCanvas read FCanvas;
public
constructor Create(ACanvas: TCanvas); virtual;
function PointInside(APoint: TPoint): Boolean; virtual; abstract;
function PointInSelectBlock(APoint: TPoint): Boolean; virtual; abstract;
function GetResizeCursorFromPoint(APoint: TPoint): TCursor; virtual; abstract;
procedure Paint; virtual; abstract;
procedure Select; virtual; abstract;
procedure Move(offsetX, offsetY: Integer); virtual; abstract;
procedure UnSelect; virtual; abstract;
property Selected: Boolean read FSelected write FSelected;
end;
TLine = class(TFigure)
private
FBeginPoint, FEndPoint: TPoint; //开始和结束位置
FSelectBlock1, FSelectBlock2: TRect; //当选中线段时,线段的两个选择块
procedure SetBeginPoint(Value: TPoint);
procedure SetEndPoint(Value: TPoint);
public
constructor Create(ACanvas: TCanvas); override;
function PointInside(APoint: TPoint): Boolean; override;
function PointInSelectBlock(APoint: TPoint): Boolean; override;
function GetResizeCursorFromPoint(APoint: TPoint): TCursor; override;
procedure Paint; override;
procedure Select; override;
procedure UnSelect; override;
procedure Move(offsetX, offsetY: Integer); override;
procedure SetBeginEndPoint(ABeginPoint, AEndPoint: TPoint);
property BeginPoint: TPoint read FBeginPoint write SetBeginPoint;
property EndPoint: TPoint read FEndPoint write SetEndPoint;
end;
implementation
{ TFigure }
{-------------------- Public --------------------}
constructor TFigure.Create(ACanvas: TCanvas);
begin
FCanvas := ACanvas;
end;
{ TLine }
{-------------------- Public --------------------}
constructor TLine.Create(ACanvas: TCanvas);
begin
inherited;
FBeginPoint := Point(0, 0);
FEndPoint := Point(0, 0);
end;
{ 判断点是否在直线里面 }
function TLine.PointInside(APoint: TPoint): Boolean;
var
iMaxX, iMinX: Integer;
iMaxY, iMinY: Integer;
k, b: Real;
begin
iMaxX := Max(FBeginPoint.X, FEndPoint.X);
iMinX := Min(FBeginPoint.X, FEndPoint.X);
iMaxY := Max(FBeginPoint.Y, FEndPoint.Y);
iMinY := Min(FBeginPoint.Y, FEndPoint.Y);
{ 如果是垂直线,则直接判断 }
if ((iMaxX - iMinX) <= 5) and ((iMaxY - iMinY) > (iMaxX - iMinX)) then
begin
Result := (Abs(APoint.X - iMaxX) <= 5) and (APoint.Y >= iMinY) and (APoint.Y <= iMaxY);
end
else begin
{ 判断公式为:y = k * x + b 斜率:k = (y2 - y1) / (x2 - x1) y轴截距:b = y1 - k * x1 }
k := (FEndPoint.Y - FBeginPoint.Y) / (FEndPoint.X - FBeginPoint.X);
b := FBeginPoint.Y - k * FBeginPoint.X;
Result := (APoint.Y <= trunc(k * APoint.X + b) + 5) and
(APoint.Y >= trunc(k * APoint.X + b) - 5);
if Result then
Result := (APoint.X >= iMinX) and (APoint.X <= iMaxX) and
(APoint.Y >= iMinY) and (APoint.Y <= iMaxY);
end;
end;
{ 判断点坐标是否在线段的选择块里面 }
function TLine.PointInSelectBlock(APoint: TPoint): Boolean;
begin
Result := PtInRect(FSelectBlock1, APoint) or PtInRect(FSelectBlock2, APoint);
end;
{ 根据点坐标在哪个选择块中,得到改变大小的光标类型 }
function TLine.GetResizeCursorFromPoint(APoint: TPoint): TCursor;
begin
Result := Screen.Cursor;
if PointInSelectBlock(APoint) then
begin
//垂直线
if FBeginPoint.X = FEndPoint.X then
Result := crSizeNS
//水平线
else if FBeginPoint.Y = FEndPoint.Y then
Result := crSizeWE
//右下斜线
else if (FBeginPoint.X - FEndPoint.X < 0) and (FBeginPoint.Y - FEndPoint.Y < 0) then
Result := crSizeNWSE
//右上斜线
else if (FBeginPoint.X - FEndPoint.X < 0) and (FBeginPoint.Y - FEndPoint.Y > 0) then
Result := crSizeNESW
//左下斜线
else if (FBeginPoint.X - FEndPoint.X > 0) and (FBeginPoint.Y - FEndPoint.Y < 0) then
Result := crSizeNWSE
//右上斜线
else if (FBeginPoint.X - FEndPoint.X > 0) and (FBeginPoint.Y - FEndPoint.Y > 0) then
Result := crSizeNWSE
end;
end;
{ 画线段 }
procedure TLine.Paint;
var
oldColor: TColor;
begin
oldColor := Canvas.Brush.Color;
if Selected then
Canvas.Brush.Color := clBlack;
Canvas.FillRect(FSelectBlock1);
Canvas.FillRect(FSelectBlock2);
Canvas.Brush.Color := oldColor;
Canvas.Pen.Mode := pmCopy;
Canvas.MoveTo(FBeginPoint.X, FBeginPoint.Y);
Canvas.LineTo(FEndPoint.X, FEndPoint.Y);
end;
{ 选中线段 }
procedure TLine.Select;
begin
Selected := True;
Paint;
end;
{ 不选中线段 }
procedure TLine.UnSelect;
begin
Selected := False;
Paint;
end;
{ 移动 }
procedure TLine.Move(offsetX, offsetY: Integer);
begin
{ 擦除原来的线段 }
Canvas.Pen.Mode := pmNotXor;
Canvas.FillRect(FSelectBlock1);
Canvas.FillRect(FSelectBlock2);
Canvas.MoveTo(FBeginPoint.X, FBeginPoint.Y);
Canvas.LineTo(FEndPoint.X, FEndPoint.Y);
SetBeginEndPoint(Point(FBeginPoint.X + offsetX, FBeginPoint.Y + offsetY),
Point(FEndPoint.X + offsetX, FEndPoint.Y + offsetY));
{ 重画 }
Paint;
end;
{ 设置线段的起始位置和终止位置 }
procedure TLine.SetBeginEndPoint(ABeginPoint, AEndPoint: TPoint);
begin
SetBeginPoint(ABeginPoint);
SetEndPoint(AEndPoint);
end;
{-------------------- Private --------------------}
{ 设置线段的开始位置 }
procedure TLine.SetBeginPoint(Value: TPoint);
begin
if (Value.X <> FBeginPoint.X) or (Value.Y <> FBeginPoint.Y) then
begin
FBeginPoint := Value;
FSelectBlock1 := Rect(FBeginPoint.X - 3, FBeginPoint.Y - 3,
FBeginPoint.X + 4, FBeginPoint.Y + 4);
end;
end;
{ 设置线段的结束位置 }
procedure TLine.SetEndPoint(Value: TPoint);
begin
if (Value.X <> FEndPoint.X) or (Value.Y <> FEndPoint.Y) then
begin
FEndPoint := Value;
FSelectBlock2 := Rect(FEndPoint.X - 3, FEndPoint.Y - 3,
FEndPoint.X + 4, FEndPoint.Y + 4);
end;
end;
end.