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
risposta
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)]);
...
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
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
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. –