2011-08-28 11 views
6

He necesitado forma propia de triángulo, heredé la clase de triángulo de TShape y anulé el método de pintura. Todo funciona bien, pero necesito mover estas formas con el mouse. Establecí el método para cada manejo de formas en el evento MoverDown. El trabajo en movimiento también está bien. Pero si dos formas se superponen (las formas son de hecho rectángulos con algunas áreas transparentes), que el área transparente de la forma superior está sobre otra, entonces la forma superior se mueve en lugar de la forma siguiente. Es correcto, así es como funciona Delphi. Pero no es intuitivo para el usuario. ¿Cómo puedo lograr eso? ¿Existe la posibilidad de no eliminar el evento de la cola del evento y enviarlo a las formas subyacentes, si es así, sería simple?Delphi - superposición de TShapes en movimiento

+4

Dibujo animaciones moviendo los controles (incluso los controles gráficos) en un formulario es malo. Si yo fuera tú, almacenaría la escena en una estructura de datos personalizada, y luego dibujaría el formulario completamente de forma manual. Entonces no hay restricciones que lo detengan: puede implementar cualquier interfaz de mouse que desee. –

Respuesta

0

Compruebe si el clic del mouse está dentro del área del triángulo antes de iniciar el movimiento de la forma. Esto requiere un poco de matemáticas, pero también se puede hacer mal uso de la función API de Windows PtInRegion mediante la creación de una región temporal, de la siguiente manera:

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

Un 'simple rediseño de la muestra' por mi comentario a continuación.

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. 

No se olvide de establecer de DoubleBuffered a true la forma.

Compilado de demostración de muestra: http://privat.rejbrand.se/MovingTriangles.exe

+0

Sé que ha pasado mucho tiempo desde que publicó esta respuesta, pero ¿tal vez podría explicar su 'InRange' para el cálculo 'min/max' de' AX'? eso me hace pensar, no he hecho matemáticas o geometría en un pensamiento de mucho tiempo. Después de mirar más, creo que comencé a entender. ¿Se reduce la mitad del triángulo pequeño potencial 'Base' con 'AY' dado al dividir 'Y-AY' (altura del triángulo pequeño) por 'Altura'? ¿Pero cómo sabes que cortar eso desde dos lados significará que 'X' está en ese rango? Hice un poco de dibujo y es verdad y ahora lo veo, pero no está tan claro cuando se hace programáticamente – Raith