2011-08-28 2 views
6

삼각형 모양이 필요하므로 삼각형 클래스 TShape 형식을 상속하고 페인트 방법을 재정의했습니다. 모든 것이 잘 작동하지만 마우스로이 모양을 옮겨야합니다. onMouseDown 이벤트를 처리하는 모든 도형에 대해 메서드를 설정했습니다. 움직이는 것도 좋습니다. 그러나 두 모양이 겹치는 경우 (모양이 실제로 일부 투명 영역이있는 사각형 임), 위쪽 모양 투명 영역이 다른 모양보다 위에 있으면 위쪽 모양이 아래 모양 대신 움직입니다. 델파이가 어떻게 작동하는지는 정확합니다. 그러나 사용자에게는 직관적이지 않습니다. 어떻게하면 될까요? 이벤트 대기열에서 이벤트를 제거하지 않고 기본 모양으로 보낸 가능성이 있습니까? 그렇다면 간단할까요?델파이 - 겹치는 TShapes 이동

+4

폼에 컨트롤 (심지어 그래픽 컨트롤) 이동 애니메이션을 그리기 나쁘다. 내가 너라면, 사용자 지정 데이터 구조에 장면을 저장 한 다음 양식을 완전히 수동으로 그릴 것입니다. 그렇다면 아무런 제약이 없습니다. 원하는 마우스 인터페이스를 구현할 수 있습니다. –

답변

0

모양 이동을 시작하기 전에 마우스 클릭이 삼각형 영역 내에 있는지 테스트합니다. 즉 약간의 수학이 필요하지만, 다음과 같이 당신은 또한, 임시 영역을 작성하여 WinAPI를 PtInRegion 기능을 악용 할 수 있습니다 : 내 댓글 당

function PtInPolygon(const Pt: TPoint; const Points: array of TPoint): Boolean; 
var 
    Region: HRGN; 
begin 
    Region := CreatePolygonRgn(Points[0], Length(Points), WINDING); 
    try 
    Result := PtInRegion(Region, Pt.X, Pt.Y); 
    finally 
    DeleteObject(Region); 
    end; 
end; 

procedure TForm1.Shape1MouseDown(Sender: TObject; Button: TMouseButton; 
    Shift: TShiftState; X, Y: Integer); 
var 
    StartMove: Boolean; 
begin 
    StartMove := PtInPolygon(Point(X, Y), [Point(100, 0), Point(200, 200), 
    Point(0, 200)]); 
    ... 
9

A '간단한 샘플 재 설계'는 다음과 같습니다.

unit Unit4; 

interface 

uses 
    Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, 
    Dialogs; 

const 
    NUM_TRIANGLES = 10; 
    COLORS: array[0..12] of integer = (clRed, clGreen, clBlue, clYellow, clFuchsia, 
    clLime, clGray, clSilver, clBlack, clMaroon, clNavy, clSkyBlue, clMoneyGreen); 

type 
    TTriangle = record 
    X, Y: integer; // bottom-left corner 
    Base, Height: integer; 
    Color: TColor; 
    end; 

    TTriangles = array[0..NUM_TRIANGLES - 1] of TTriangle; 

    TForm4 = class(TForm) 
    procedure FormCreate(Sender: TObject); 
    procedure FormPaint(Sender: TObject); 
    procedure FormMouseDown(Sender: TObject; Button: TMouseButton; 
     Shift: TShiftState; X, Y: Integer); 
    procedure FormMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); 
    procedure FormMouseUp(Sender: TObject; Button: TMouseButton; 
     Shift: TShiftState; X, Y: Integer); 
    private 
    { Private declarations } 
    FTriangles: TTriangles; 
    FDragOffset: TPoint; 
    FTriangleActive: boolean; 
    function GetTriangleAt(AX, AY: Integer): Integer; 
    function IsMouseDown: boolean; 
    public 
    { Public declarations } 
    end; 

var 
    Form4: TForm4; 

implementation 

uses Math; 

{$R *.dfm} 


procedure TForm4.FormCreate(Sender: TObject); 
var 
    i: Integer; 
begin 
    FTriangleActive := false; 
    Randomize; 
    for i := 0 to NUM_TRIANGLES - 1 do 
    with FTriangles[i] do 
    begin 
     base := 40 + Random(80); 
     height := 40 + Random(40); 
     X := Random(ClientWidth - base); 
     Y := height + Random(ClientHeight - height); 
     Color := RandomFrom(COLORS); 
    end; 
end; 

procedure TForm4.FormMouseDown(Sender: TObject; Button: TMouseButton; 
    Shift: TShiftState; X, Y: Integer); 
var 
    TriangleIndex: integer; 
    TempTriangle: TTriangle; 
    i: Integer; 
begin 
    TriangleIndex := GetTriangleAt(X, Y); 
    if TriangleIndex <> -1 then 
    begin 
    FDragOffset.X := X - FTriangles[TriangleIndex].X; 
    FDragOffset.Y := Y - FTriangles[TriangleIndex].Y; 
    TempTriangle := FTriangles[TriangleIndex]; 
    for i := TriangleIndex to NUM_TRIANGLES - 2 do 
     FTriangles[i] := FTriangles[i + 1]; 
    FTriangles[NUM_TRIANGLES - 1] := TempTriangle; 
    Invalidate; 
    end; 
    FTriangleActive := TriangleIndex <> -1; 
end; 

function TForm4.IsMouseDown: boolean; 
begin 
    result := GetKeyState(VK_LBUTTON) and $8000 <> 0; 
end; 

procedure TForm4.FormMouseMove(Sender: TObject; Shift: TShiftState; X, 
    Y: Integer); 
begin 
    if IsMouseDown and FTriangleActive then 
    begin 
    FTriangles[high(FTriangles)].X := X - FDragOffset.X; 
    FTriangles[high(FTriangles)].Y := Y - FDragOffset.Y; 
    Invalidate; 
    end; 
end; 

procedure TForm4.FormMouseUp(Sender: TObject; Button: TMouseButton; 
    Shift: TShiftState; X, Y: Integer); 
begin 
    FTriangleActive := false; 
end; 

procedure TForm4.FormPaint(Sender: TObject); 
var 
    i: Integer; 
    Vertices: array of TPoint; 
begin 
    SetLength(Vertices, 3); 
    for i := 0 to NUM_TRIANGLES - 1 do 
    with FTriangles[i] do 
    begin 
     Canvas.Brush.Color := Color; 
     Vertices[0] := Point(X, Y); 
     Vertices[1] := Point(X + Base, Y); 
     Vertices[2] := Point(X + Base div 2, Y - Height); 
     Canvas.Polygon(Vertices); 
    end; 
end; 

function TForm4.GetTriangleAt(AX, AY: Integer): Integer; 
var 
    i: Integer; 
begin 
    result := -1; 
    for i := NUM_TRIANGLES - 1 downto 0 do 
    with FTriangles[i] do 
     if InRange(AY, Y - Height, Y) and 
     InRange(AX, round(X + (Base/2) * (Y - AY)/Height), 
      round(X + Base - (Base/2) * (Y - AY)/Height)) then 
     Exit(i); 
end; 

end. 

설정하는 것을 잊지 마세요 형태의 DoubleBuffered true합니다.

컴파일 샘플 데모 : http://privat.rejbrand.se/MovingTriangles.exe

+0

이 답변을 게시 한 이후로 오랜 시간이 걸렸으나 'AX'분/최대 계산에 대해 'InRange'를 설명 할 수 있습니까? 그 종류의 불면 내 마음, 나는 수학이나 기하학을 오랫동안 생각 havent. 더 많이 응시 한 후에 나는 내가 이해하기 시작했다고 생각한다. 'Y-AY'(작은 삼각형 높이)를 '높이'로 나누면 주어진 'AY'를 사용하여 잠재적 인 작은 삼각형 '기본'의 절반을 축소 할 수 있습니까? 그러나 양면에서 절단하는 것이 'X'가 그 범위에 있다는 것을 어떻게 알 수 있습니까? 나는 약간의 그림을 그렸고 그것은 사실이며 지금은 그것을 볼 수 있지만 프로그래밍 방식으로 완료했을 때 분명하지는 않습니다. – Raith