谁能帮忙诊断一段程序(100分)

  • 主题发起人 主题发起人 的士
  • 开始时间 开始时间

的士

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.
 
主要问题是出现在Paint方法和Move方法中,
如果去除了FillRect,就不会出错。
 
试一下把画线的时候用pen.mode:=pmnotxor;
而move 时,mode:=pmnot;
 
试了,还是会留下“垃圾”的。
 
想法有问题,想实现这个功能,要从全局考虑,你的canvas上要是有背景怎么办,仅仅是纯色的背景已经
有很多问题了,你画的时候不是用异或,想移走时用异或。要想实现这样的功能,我看还是用图层吧,不
然不会有什么结果的。PAINT过程可不是应该管canvas的,要是管了,就不是tline了
 
那个Canvas是TImage.
 
问题是你的Move实现的有问题,在Move过程中一直是处于异或绘图方式,在Move结束才重绘.你的Move中
调用Paint,里面的绘图方式是Copy!当然是垃圾了。
 
NoSwing:那请问Move方法和Paint方法应该如何改。
 
我把Move方法改为下面的还是一样呀。

{ 移动 }
procedure TLine.Move(offsetX, offsetY: Integer);
var
oldColor: TColor;
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));

oldColor := Canvas.Brush.Color;
if Selected then
Canvas.Brush.Color := clBlack;
Canvas.FillRect(FSelectBlock1);
Canvas.FillRect(FSelectBlock2);
Canvas.Brush.Color := oldColor;
Canvas.MoveTo(FBeginPoint.X, FBeginPoint.Y);
Canvas.LineTo(FEndPoint.X, FEndPoint.Y);
end;
 
晕倒,大哥,移动时不要用 FILLRECT否则很会出问题的!
 
多人接受答案了。
 
后退
顶部