请参考这个帖子(http://www.delphibbs.com/delphibbs/dispq.asp?lid=1661776)中我的控件,为了避免挡住其他的控件,对它进行了修改,附于下面。当然,还有一些代码你得自己完成。
unit LinLine;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, ExtCtrls, CommCtrl;
type
TFrameType = (ftOuter,ftInner,ftMiddle);
TDragBox = (dbNone,dbDrag,dbPoint1,dbPoint2);
TOnPaintEvent = procedure (Sender: TObject; Canvas: TCanvas; Rect: TRect) of object;
TLinLine = class(TGraphicControl)
private
{ Private declarations }
FPoint1,FPoint2:TPoint;
FHasInit:Boolean;
FAutoForeGround: Boolean;
FReadOnly: Boolean;
FOnPaint: TOnPaintEvent;
FFrameType: TFrameType;
FAutoSize: Boolean;
FCaption: String;
FHideFrame: Boolean;
FFrameColor: TColor;
FBoxSize: Integer;
FBoxColor: TColor;
FActiveFrameColor: TColor;
FPassiveFrameColor: TColor;
FTextColor: TColor;
FDrawFrame: Boolean;
FDrawBoxes: Boolean;
FShowPos: Boolean;
FShowSize: Boolean;
FDragBox: TDragBox;
FPosX: Integer;
FPosY: Integer;
FHasFocus: Boolean;
procedure WMGetDlgCode(var Message: TWMGetDlgCode); message WM_GETDLGCODE;
procedure SetFocus(Value: Boolean);
procedure SetAutoSize(Value: Boolean);
procedure SetHideFrame(Value: Boolean);
procedure SetCaption(Value: String);
procedure SetFrameBox(PLeft,PTop,PWidth,PHeight: Integer);
procedure SetFrameType(Value: TFrameType);
procedure SetBoxSize(Value: Integer);
procedure SetBoxColor(Value: TColor);
procedure SetActiveFrameColor(Value: TColor);
procedure SetPassiveFrameColor(Value: TColor);
procedure SetTextColor(Value: TColor);
procedure SetDrawFrame(Value: Boolean);
procedure SetDrawBoxes(Value: Boolean);
procedure SetShowPos(Value: boolean);
procedure SetShowSize(Value: Boolean);
procedure WMLMouseDown(var Message: TMessage); message WM_LBUTTONDOWN;
procedure WMLMouseUp(var Message: TMessage); message WM_LBUTTONUP;
procedure MouseMove(Sender: TObject; Shift: TShiftState; X,Y: Integer);
procedure FormMouseMove(Sender: TObject; Shift: TShiftState; X,Y: Integer);
function NearLine(X,Y: Integer):boolean;
protected
procedure paint; override;
public
procedure RemoveAllFocus;
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
published
property AutoForeGround: Boolean read FAutoForeGround write FAutoForeGround;
property AutoSize: Boolean read FAutoSize write SetAutoSize;
property FrameType: TFrameType read FFrameType write SetFrameType;
property HidePassiveFrame: Boolean read FHideFrame write SetHideFrame;
property Caption: String read FCaption write SetCaption;
property BoxSize: Integer read FBoxSize write SetBoxSize;
property BoxColor: TColor read FBoxColor write SetBoxColor;
property ActiveFrameColor: TColor read FActiveFrameColor write SetActiveFrameColor;
property PassiveFrameColor: TColor read FPassiveFrameColor write SetPassiveFrameColor;
property DrawFrame: Boolean read FDrawFrame write SetDrawFrame;
property DrawBoxes: Boolean read FDrawBoxes write SetDrawBoxes;
property ShowPos: Boolean read FShowPos write SetShowPos;
property ShowSize: Boolean read FShowSize write SetShowSize;
property InfoTextColor: TColor read FTextColor write SetTextColor;
property Focus: Boolean read FHasFocus write SetFocus;
property Font;
property OnClick;
property PopupMenu;
property OnMouseDown;
property OnMouseMove;
property OnMouseUp;
property OnDblClick;
property OnStartDrag;
property OnDragOver;
property OnDragDrop;
property OnEndDrag;
property OnPaint: TOnPaintEvent read FOnPaint write FOnPaint;
end;
procedure Register;
implementation
procedure Register;
begin
RegisterComponents('DPD', [TLinLine]);
end;
function between(PVal1,PVal2,PVal3: Integer):Boolean;
begin
if (PVal1 > PVal2) and (PVal1 < PVal3) then Result := True
else if (PVal1 > PVal3) and (PVal1 < PVal2) then result := True
else Result := False;
end;
constructor TLinLine.Create(AOwner: TComponent);
begin
inherited create(AOwner);
FBoxColor := clBlack;
FActiveFrameColor := clBlack;
FPassiveFrameColor := clGray;
FBoxSize := 5;
Height:=10; ////
Width:=20; ////
FHasInit:=false;
FDrawBoxes := True;
FDrawFrame := True;
FFrameType := ftOuter;
FAutoForeGround := True;
OnMouseMove := MouseMove;
end;
destructor TLinLine.Destroy;
begin
inherited Destroy;
end;
procedure TLinLine.Paint;
var
LHalfBox: Integer;
LRect,LClient: TRect;
Point1,Point2:Tpoint;
//StrTmp:string;
begin
if FAutoSize then SetBounds(Left,Top,Canvas.Textwidth(FCaption),Canvas.TextHeight(FCaption));
LRect := ClientRect;
if FFrameType = ftOuter then LHalfBox := 0
else if FFrameType = ftInner then LHalfBox := FBoxSize
else LHalfBox := (FBoxSize div 2);
if (not FHasInit) or (csDesigning in ComponentState) then
begin
FPoint1:=point(Left +FBoxSize ,top +FBoxSize );
FPoint2:=point(left+width -FBoxSize ,top+FBoxSize );
FHasInit:=true;
end;
//Calculate Client area that does not intercept the drag boxes;
LRect.Left := LRect.Left + LHalfBox + 1;
LRect.Right := LRect.Right - LHalfBox - 1;
LRect.Top := LRect.Top - LHalfBox;
LRect.Bottom := LRect.Bottom - LHalfBox - 1;
//client Area as defined by the frame drawn
LClient.Left := LHalfBox;
LClient.Top := LHalfBox;
LClient.right := width-1 - LHalfBox;
LClient.Bottom := Height - 1 - LHalfBox;
Point1:=ScreenToClient( Parent.ClientToScreen(FPoint1));
Point2:=ScreenToClient( Parent.ClientToScreen(FPoint2));
////MessageDlg(IntToStr(Point1.x)+':'+IntToStr(Point1.y)+':'+IntToStr(Point2.x)+':'+IntToStr(Point2.y), mtInformation, [mbOk], 0);
if assigned(FOnPaint) then FOnPaint(Self,Canvas,LClient);
//draw the frame
if (FHasFocus and DrawFrame) or (not FHasFocus and not FHideFrame) then begin
if FDrawFrame then begin
canvas.pen.color := FFrameColor;
Canvas.MoveTo(Point1.x,Point1.y+ LHalfBox);
Canvas.LineTo(Point2.x,Point2.y+ LHalfBox);
//Canvas.MoveTo(LClient.left,LClient.top);
//Canvas.LineTo(LClient.right,LClient.bottom);
end;
end;
//Draw the drag boxes
LHalfBox := (FBoxSize div 2);
if FDrawBoxes and (FHasFocus or (csDesigning in ComponentState)) then begin
Canvas.brush.color := FBoxColor;
Canvas.FillRect(rect(Point1.x - LHalfBox ,Point1.y - LHalfBox ,Point1.x + LHalfBox ,Point1.y + LHalfBox));
Canvas.FillRect(rect(Point2.x - LHalfBox ,Point2.y - LHalfBox ,Point2.x + LHalfBox ,Point2.y + LHalfBox));
end;
//Set the fixed font for the optional position information
Canvas.Font.Color := FTextColor;
Canvas.Brush.style := bsClear;
canvas.font.Name := 'MS Sans Serif';
canvas.font.Style := [];
canvas.font.height := 10;
if FShowPos and FHasFocus then begin
Canvas.Brush.style := bsClear;
Canvas.TextRect(LRect,FBoxSize+ 2,FBoxSize,'L:' + IntToStr(Left) + ' T:' + IntToStr(Top));
end;
if FShowSize and FHasFocus then begin
Canvas.TextRect(LRect,FBoxSize + 2,FBoxSize + (Canvas.font.Height * 1) + 3,'W:' + IntToStr(Width) + ' H:' + IntToStr(Height));
end;
Canvas.Font := Font;
Canvas.TextRect(LRect,(Width - Canvas.Textwidth(FCaption)) div 2,(Height - Canvas.TextHeight(FCaption)) div 2,FCaption);
//StrTmp:=IntToStr(Point1.x)+':'+IntToStr(Point1.y)+':'+IntToStr(Point2.x)+':'+IntToStr(Point2.y);
//Canvas.TextRect(LRect,2,2,Strtmp);
end;
procedure TLinLine.SetFrameType(Value: TFrameType);
begin
if FFrameType = Value then exit;
FFrameType := Value;
Invalidate;
end;
procedure TLinLine.SetBoxSize(Value: Integer);
begin
if Value = FBoxSize then exit;
if value < 2 then exit;
if value > 50 then exit;
FBoxSize := ((Value div 2) * 2) + 1; //保证是一个奇数
invalidate;
end;
procedure TLinLine.SetBoxColor(Value: Tcolor);
begin
if Value = FBoxColor then exit;
FBoxColor := Value;
invalidate;
end;
procedure TLinLine.SetActiveFrameColor(Value: Tcolor);
begin
if Value = FActiveFrameColor then exit;
FActiveFrameColor := Value;
invalidate;
end;
procedure TLinLine.SetPassiveFrameColor(Value: Tcolor);
begin
if Value = FPassiveFrameColor then exit;
FPassiveFrameColor := Value;
invalidate;
end;
procedure TLinLine.SetTextColor(Value: Tcolor);
begin
if Value = FTextColor then exit;
FTextColor := Value;
invalidate;
end;
procedure TLinLine.SetDrawFrame(Value: Boolean);
begin
if Value = FDrawFrame then exit;
FDrawFrame := Value;
invalidate;
end;
procedure TLinLine.SetDrawBoxes(Value: Boolean);
begin
if Value = FDrawBoxes then exit;
FDrawBoxes := Value;
invalidate;
end;
procedure TLinLine.SetShowPos(Value: boolean);
begin
if Value = FShowPos then exit;
FShowPos := Value;
invalidate;
end;
procedure TLinLine.SetShowSize(Value: Boolean);
begin
if Value = FShowSize then exit;
FShowSize := Value;
invalidate;
end;
procedure TLinLine.WMLMouseDown(var Message: TMessage);
begin
FPosX := Message.LParamLo;
FposY := Message.LParamHi;
if not NearLine(X,Y) then
begin
//向下层控件发送被点击的消息
end;
if FAutoForeGround then BringToFront;
if (Message.WParamLo <> 5) then begin
if FHasFocus =false then begin
RemoveAllFocus;
FHasFocus := True;
end;
end else //Shift按键被按下,要多选
FHasFocus := not FHasFocus;
if FHasFocus then begin
FFrameColor := FActiveFrameColor;
SetCapture(TForm(Parent).handle);
TForm(Parent).OnMouseMove := FormMouseMove;
end;
invalidate;
end;
procedure TLinLine.WMLMouseUp(var Message: TMessage);
begin
releaseCapture;
FPosX := -1;
FPosY := -1;
FDragBox := dbNone;
invalidate
end;
procedure TLinLine.FormMouseMove(Sender: TObject; Shift: TShiftState; X,Y: Integer);
var
LPoint: TPoint;
begin
//Translate coodinates to object
LPoint := ScreenToClient( Tform(Parent).ClientToScreen(point(X,Y)));
MouseMove(Sender,Shift,LPoint.X,Lpoint.Y);
end;
procedure TLinLine.MouseMove(Sender: TObject; Shift: TShiftState; X,Y: Integer);
var
Point1, Point2: TPoint;
HalfBoxSize,Temp:integer;
begin
//Prepare some variables
HalfBoxSize:=FBoxSize div 2;
Point1:=ScreenToClient( parent.ClientToScreen(FPoint1));
Point2:=ScreenToClient( parent.ClientToScreen(FPoint2));
if not (ssLeft in Shift) then begin
FDragBox := dbNone;
//Check if cursor is over any of the most left boxes
if (between(X,Point1.x - HalfBoxSize,Point1.x + HalfBoxSize) and between(Y,Point1.y - HalfBoxSize,Point1.y + HalfBoxSize)) then begin Cursor := crSizeALL; FDragBox := dbPoint1; end
else if (between(X,Point2.x - HalfBoxSize,Point2.x + HalfBoxSize) and between(Y,Point2.y - HalfBoxSize,Point2.y + HalfBoxSize)) then begin Cursor := crSizeALL; FDragBox := dbPoint2; end
else if (between(X,0,width) and between(Y,0,Height) ) or (FHasFocus and (ssShift in shift))then begin Cursor := crDefault; FDragBox := dbDrag; end; //用点到直线的距离来解决拖动问题
end else begin
//Make size changes if clicked
if (FPosX >= 0) and (FPosY >= 0 ) then begin
if FDragBox = dbPoint1 then begin
Point1.x:=X;Point1.y:= Y ;
FPoint1:=parent.ScreenToClient( ClientToScreen(Point1));
Temp:=Point1.x;
if Point2.x<Point1.x then begin
Point1.X:=Point2.x;
Point2.X:=Temp;
end;
Temp:=point1.Y;
if Point2.y<Point1.y then begin
Point1.Y:=Point2.y;
Point2.Y:=Temp;
end;
Point1:=parent.ScreenToClient( ClientToScreen(Point1));
Point2:=parent.ScreenToClient( ClientToScreen(Point2));
SetFrameBox(Point1.X - HalfBoxSize,Point1.Y - HalfBoxSize,Point2.X - Point1.X + FBoxSize,Point2.Y - Point1.Y + FBoxSize);
end else if FDragBox = dbPoint2 then begin
Point2.x:=X ;Point2.y:=Y ;
FPoint2:=parent.ScreenToClient( ClientToScreen(Point2));
Temp:=Point1.x;
if Point2.x<Point1.x then begin
Point1.X:=Point2.x;
Point2.X:=Temp;
end;
Temp:=point1.Y;
if Point2.y<Point1.y then begin
Point1.Y:=Point2.y;
Point2.Y:=Temp;
end;
Point1:=parent.ScreenToClient( ClientToScreen(Point1));
Point2:=parent.ScreenToClient( ClientToScreen(Point2));
SetFrameBox(Point1.X - HalfBoxSize,Point1.Y - HalfBoxSize,Point2.X - Point1.X + FBoxSize,Point2.Y - Point1.Y + FBoxSize);
end else if FDragBox = dbDrag then begin
FPoint1.X:=FPoint1.X+ X - FPosX;
FPoint1.Y:=FPoint1.Y+ Y - FPosY;
FPoint2.X:=FPoint2.X+ X - FPosX;
FPoint2.Y:=FPoint2.Y+ Y - FPosY;
SetFrameBox(Left - (FPosX - X),Top - (FPosY - Y),Width,Height);
invalidate;
end;
end;
end;
end;
function TLinLine.NearLine(X,Y: Integer):boolean;
begin
result := (self.Canvas.Pixels(X,Y)= self.FFrameColor) or (self.Canvas.Pixels(X-1,Y)= self.FFrameColor) or (self.Canvas.Pixels(X,Y -1)= self.FFrameColor) or (self.Canvas.Pixels(X+1,Y)= self.FFrameColor)or (self.Canvas.Pixels(X,Y+1)= self.FFrameColor) then
end;
procedure TLinLine.SetFrameBox(PLeft,PTop,PWidth,PHeight: Integer);
begin
if (PWidth < FBoxSize) or (PHeight < FBoxSize) then exit;
SetBounds(PLeft,PTop,PWidth,PHeight);
end;
procedure TLinLine.WMGetDlgCode(var Message: TWMGetDlgCode);
begin
inherited;
Message.Result := DLGC_WANTARROWS;
end;
procedure TLinLine.SetCaption(Value: String);
begin
if Value = FCaption then exit;
FCaption := Value;
invalidate;
end;
procedure TLinLine.SetHideFrame(Value: Boolean);
begin
if Value = FHideFrame then exit;
FHideFrame := Value;
Invalidate;
end;
procedure TLinLine.SetAutoSize(Value: Boolean);
begin
if Value = FAutoSize then exit;
FAutoSize := Value;
invalidate;
end;
procedure TLinLine.RemoveAllFocus;
//var
// i: Integer;
// LRectBox: TLinLine;
begin
SendMessage (parent.Handle, WM_RBUTTONDOWN,0, MakeLong (0, 0));
application.ProcessMessages;
application.ProcessMessages;
// for i := 0 to Owner.ComponentCount - 1 do begin
// if Owner.Components is TLinLine then begin
// LRectBox := TLinLine(Owner.Components);
// if LRectBox.FHasFocus then begin
// LRectBox.FHasFocus := False;
// LRectBox.Invalidate;
// end;
// end;
// end;
end;
procedure TLinLine.SetFocus(Value: Boolean);
begin
if Value = FHasFocus then exit;
FHasFocus := Value;
invalidate;
end;
end.