'Objekte' erscheinen und verschwinden lassen

Hallo!

Vieleicht kann mir hier jemand verständlich helfen?
Danke.

  1. Problem:

Ich hab eine Klasse. Nennen wir sie TViereck. In der Type Deklaration (abgeleitet von „class(TObject)“)gibt es noch zusätzlich eine Farbe, eine Größe und die X Y Position. Dann benötigen wir ein Objekt, Nennen wir es LBehälter vom Type TObjectList.
Beim Starten des Programms wird Object kreiert. Mit der Maus clicke ich auf mein Formular und ein „NeuesViereck“ wird erzeugt und auf dem „canvas“ vom TForm angezeigt. Gleichzeitig wird dieses Object in LBehälter gesammelt. So kann ich nun meine Form zupunkten.

Frage:

Wie bekomme ich es hin, das das richtige Viereck unter dem Mauszeiger als „selectiert (Strichellinie)“ angezeigt wird wenn ich darüber fahre und beim rechtsclick soll dieses und nur dieses verschwinden.:smile:

-((( Bei mir verschwinden immer alle und eine Selectierung habe ich noch nicht hinbekommen :frowning:((

Hallo,

die Canvas ist ja nur eine Zeichenfläche, die Pixel darstellt. Welcher Pixel jetzt hinter welchem Objekt liegt, weiß die Canvas nicht.

Wenn Du nur einfache geometrische Objekte brauchst, nimm TShape und eine ObjectList (oder ab D2009 auch einen entsprechenden generischen Typ TList) oder du benutzt andere Komponenten, die einzelne Canvas’ zur Verfügung stellen zB TPanel und zeichnest auf diese. Dann kannst Du alle Routinen der entsprechenden Objekte verwenden. Evtl kannst Du Deine Objekte auch von diesen Komponenten ableiten und Deinen Bedürfnissen entsprechend erweitern und bekommst damit eigenen Komponenten.

Gruß, Niels

Hallo,

offensichtlich hast du ja alle Figuren LBehälter. Im OnPaint-Ereignis des Fensters gehst du dann ja sicher diese Liste durch, um die Figuren zu zeichnen.

Wenn du die Maus über das Fenster bewegst, wird - wie du auch sicher weist - immer ein OnMouseMove-Ereignis ausgelöst. Dabei wird die aktuelle X- und Y-Koordinale ter Maus übergeben. Hier musst du herausfinden, innerhalb welcher Figuren (in LBehälter) sich diese Koordinate befindet.

Wenn du einfache Rechtecke hast, geht das mit der Funktion PtInRect. Bei komplizierteren Formen musst du halt die Geometrie bemühen :smile:. Am saubersten verpasst du deinem Figur-Objekt eine Methode, die für den Objekttyp und die Instanz eben prüft, ob ein gegebener Punkt in der Figur liegt, also zB.

function TViereck.isPointInFigure(P:TPoint):Boolean;
var
 R:TRect;
begin
 R := Rect(X,Y,X+Breite,Y+Hoehe); // das musst du natürlich so 
 // setzen, wie du die Position
 // und Größe von TViereck
 // definiert hast
 Result := PtInRect(P, R);
end;

Für einen Kreis mit Mittelpunkt (X|Y) und Radius R könnte die Methode dann so aussehen:

function TKreis.isPointInFigure(P:TPoint):Boolean;
begin
 Result := ((X-P.X)^2 + (Y-P.Y)^2) 

Im OnMouse-Move-Ereignishandler gehst du dann einfach die LBehälter-Liste durch und prüft jede dort abgelegte Figur. Ist der Rückgabewert Wahr, dann hast du die Figur identifiziert. Wenn du "von hinten nach vorne" suchst, findest du die zuletzt hinzugefügte, also "obere" Figur zuerst:



    
     P := Point(X,Y);
     for i := LBehälter.Count-1 downto 0 do
     if TViereck(LBehälter[i]).isPointInFigure(P) then
     begin
     // gefunden! mach was damit!
     Break; // nicht mehr weitersuchen; wir sind fertig.
     end;



So, du willst die selektierte Figur "markieren". Dazu würde ich die Nummer der Figur irgendwie sichern und in der Paint-Methode, wo alle Figuren gezeichnet werden, abfragen, ob die zu zeichnende Figur die "markierte" ist und sie entsprechend anders zeichnen.

Ich schlage mal vor (es gibt 1001 andere Möglichkeiten!), den Index der selektierten Figur in LBehälter in einer Integer-Variable des Formulars zu speichern. Nennen wir sie "Selected".

Im Mouse-Move-Handler setzt du Selected := i, wenn du die Figur gefunden hast. Wurde keine gefunden, kannst du Selected auf -1 setzen. Um nicht immer alles neu zeichnen zu müssen, wenn sich die Selektion nicht ändert, solltest du die vorige Selektion zwischenspeichern und prüfen. Alles in allem könnte das so aussehen:



    
     oldSelected := Selected;
     Selected := -1;
     P := Point(X,Y);
     for i := LBehälter.Count-1 downto 0 do
     if TViereck(LBehälter[i]).isPointInFigure(P) then
     begin
     Selected := i;
     Break; 
     end;
     if oldSelected Selected then Repaint;




Im OnMouseDown-Handler kannst du dann ebenfalls anhand des Wertes von Selected das entsprechende Objekt aus LBehälter löschen und den ganzen Ramsch neu zeichnen:



    
     if Selected \>= 0 then // nur, wenn auch wirklich was selektiert ist
     begin
     LBehälter.Delete(Selected);
     Selected := -1;
     Repaint;
     end;




Damit solltest du klarkommen...


VG
Jochen

PS: Man könnte im Formular eine "SelectFigureAt"-Methode schreiben, die genau das macht, was ich oben im MouseMove-Handler geschrieben habe. Diese Methode könnte man dann im MouseMove-Handler aufrufen und außerdem im ButtonDown-Handler nach dem Löschen, um sofort die nächste Figur unter dem mauszeiger auszuwählen.

PPS: Die ganze Sache eignet sich schön für eine Virtualisierung. Man kann eine abstrakte "TFigur"-Klasse definieren, mit virtuellen Methoden fürs Erstellen, Zeichnen und für die Prüfung, ob eine Koordinate in der Figur ist. Diese Methoden kann man dann in abgeleiteten Klassen wie TViereck, TKreis, TDreieck usw. überschreiben. Woimmer in Formular dann auf ein LBehälter-Objekt zugegriffen wird, fasst man es als TFigur-Instanz auf, womit dann automatisch dir korrekte virtuelle, überschriebene Methode für das betreffende Objekt verwendet wird.

Hallo Jo…!

Danke für die Antwort. Ich werde es einmal ausprobieren. So ähnlich habe ich es mir auch vorgestellt. Ich bitte um Entschuldigung, das ich nicht gleich geantwortet habe, aber ich mußte arbeiten und am späten Abend habe ich keinen Nerv mehr dafür.
Also Danke und bis dahin…
Marcus

Hallo Niels!

Danke für die schnelle Antwort. Ich weiß, das der Canvas nur eine Zeichenfläche ist, und ich hätte gern auch z.B. ein TShape oder so verwendet. Aber mein Lehrer hat mir genau diese Aufgabe gestellt. Nun bin ich kein Profi, sondern in Delphi ein Neueinsteiger. Aber es muß eine Lösung geben. Ich werde übers WE noch ein wenig weiterknobeln. Notfals melde ich mich wieder.
Danke bis dahin…
Marcus