2011-08-28 4 views
6

J'ai besoin de la forme de triangle propre, j'ai hérité mon formulaire de classe triangle TShape et remplacer la méthode de peinture. Tout fonctionne bien, mais j'ai besoin de déplacer ces formes avec la souris. J'ai défini la méthode pour chaque événement de gestion de forme onMouseDown. Déménagement travail aussi bien. Mais si deux formes se chevauchent (les formes sont en fait des rectangles avec des zones transparentes), que la surface transparente de la forme du dessus est sur une autre forme, alors la forme supérieure se déplace au lieu de la forme ci-dessous. C'est correct, c'est comme ça que Delphi fonctionne. Mais ce n'est pas intuitif pour l'utilisateur. Comment puis-je y parvenir? Est-il possible de ne pas supprimer l'événement de la file d'attente des événements et l'envoyer aux formes sous-jacentes, si oui, ce serait simple?Delphi - se déplaçant chevauchant TShapes

+4

animations Dessin par le déplacement des contrôles sur un formulaire (même les contrôles graphiques) est mauvaise. Si j'étais vous, je stockerais la scène dans une structure de données personnalisée, puis dessinerais le formulaire complètement manuellement. Ensuite, aucune restriction ne vous retient - vous pouvez implémenter n'importe quelle interface de souris. –

Répondre

0

Vérifiez si le clic de la souris est dans la zone du triangle avant de commencer à déplacer la forme. Cela nécessite un peu de maths, mais vous pouvez aussi abuser de la fonction WinAPI PtInRegion en créant une région temporaire, comme suit:

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 « refonte simple échantillon » par mon commentaire suit.

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. 

Ne pas oublier de mettre DoubleBuffered à true de la forme.

échantillon Compilé demo: http://privat.rejbrand.se/MovingTriangles.exe

+0

Je sais que cela fait longtemps que vous n'avez pas posté cette réponse, mais peut-être pourriez-vous expliquer votre 'InRange' pour le calcul min/max de' AX'? ce genre de souffle dans mon esprit, je n'ai pas fait de maths ou de géométrie depuis longtemps. Après avoir regardé plus, je pense que j'ai commencé à comprendre. Vous réduisez la moitié du plus petit triangle potentiel 'Base' avec' AY' donné en divisant 'Y-AY' (petit triangle) par' Height'? Mais comment savez-vous que couper cela de deux côtés signifie que «X» est dans cette gamme? J'ai fait du dessin et c'est vrai et maintenant je le vois, mais ce n'est pas aussi clair quand on le fait par programmation – Raith