2011-08-28 7 views
6

Ho avuto bisogno della propria forma triangolare così, ho ereditato il mio modulo di classe triangolo TShape e sovrascrivi il metodo di pittura. Tutto funziona bene, ma ho bisogno di spostare queste forme con il mouse. Ho impostato il metodo per ogni gestione della forma sull'evento MainDown. Anche il lavoro in movimento va bene. Ma se due forme si sovrappongono (le forme sono in realtà rettangoli con alcune aree trasparenti), che l'area trasparente della parte superiore è sopra un'altra forma, quindi la forma superiore si sposta invece della forma sottostante. È corretto, è così che funziona Delphi. Ma non è intuitivo per l'utente. Come posso ottenerlo? C'è la possibilità di non rimuovere l'evento dalla coda degli eventi e inviarlo a forme sottostanti, se sì sarebbe semplice?Delphi - spostamento di forme sovrapposte TS

+4

Disegno animazioni spostando controlli (anche controlli grafici) in un modulo è male. Se fossi in te, memorizzerei la scena in una struttura dati personalizzata e quindi disegnerei il modulo completamente manualmente. Quindi non ci sono restrizioni che ti trattengono: puoi implementare qualsiasi interfaccia del mouse che desideri. –

risposta

0

Verificare se il clic del mouse si trova nell'area del triangolo prima di iniziare a spostare la forma. Questo richiede un po 'di matematica, ma si potrebbe anche abusare della funzione WinAPI PtInRegion con la creazione di una regione temporanea, come segue:

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 'semplice riprogettazione campione' per il mio commento segue.

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. 

Non dimenticare di impostare il DoubleBuffered per true modulo.

Compilato campione demo: http://privat.rejbrand.se/MovingTriangles.exe

+0

So che è passato molto tempo da quando hai postato questa risposta, ma forse potresti spiegare il tuo 'InRange' per il calcolo min/max di' AX'? quel tipo di colpi alla testa, non ho fatto matematica o geometria da molto tempo. Dopo altri fissi, penso di aver iniziato a capire. Ridimensionate la metà del triangolo più piccolo 'Base' con dato 'AY' dividendo' Y-AY' (altezza triangolo piccolo) per 'Altezza'? Ma come sai che tagliandolo da due lati significherà che 'X' è in quella gamma? Ho fatto un disegno ed è vero e ora lo vedo, ma non è così chiaro quando viene fatto programmaticamente però – Raith