![]() |
TLine - Canvas an Line ausrichten
Liste der Anhänge anzeigen (Anzahl: 1)
Ich erstelle z.Z eine TLine Klasse (Shape).
Dabei habe Ich folgendes Problem: Damit die Line vollständig in das Canvas hineinpasst, muß man beim Zeichnen der Linie Offsets abziehen. Wenn man das aber tut, wird die Linie zwar schön dargestellt (Siehe Paint), aber sie stimmt nicht mehr, weder Start- noch Endpunkt. Man sieht auch, daß der Winkel falsch ist (Siehe Anlage). Ich müßte die ganze Komponente andersrum aufziehen. Zwei Eckpunkte vorgeben und die Komponentengröße wird dann entsprechend berechnet (statt die Linie einzupassen). Es wäre auch schön, wenn das auch schon zur Designzeit so angezeigt werden könnte. Da ich von Grafikprogrammierung nur wenig Ahnung habe, wolle ich mal fragen, wie könnte man denn so was machen? TLine ist z.Z. von TGraphicControl abgeleitet? Edit: Crosspost vergessen ![]()
Delphi-Quellcode:
Zum besseren Verständnis hab ich einem Image die korrekte Line mal gezeichnet.
function TLine.OffSet1: integer;
begin Result := FPen.Width div 2; end; function TLine.OffSet2: integer; begin Result := OffSet1 + FPen.Width mod 2; end; procedure TLine.Paint; var X1, Y1, X2, Y2: Integer; begin with Canvas do begin Pen := FPen; X1 := 0; Y1 := 0; X2 := Width; Y2 := Height; if X2 < 0 then begin Dec(X1, OffSet2); Inc(X2, OffSet1); end else begin Inc(X1, OffSet1); Dec(X2, OffSet2); end; if Y2 < 0 then begin Dec(Y1, OffSet2); Inc(Y2, OffSet1); end else begin Inc(Y1, OffSet1); Dec(Y2, OffSet2); end; MoveTo(X1, Y1); LineTo(X2, Y2); end; end; |
AW: TLine - Canvas an Line ausrichten
Deine Linien Komponente bräuchte ein Property mit dem angegeben wird wie die Linie im umgebenden "Kasten" ausgerichtet sein soll.
Delphi-Quellcode:
Bei laLeft und laRight kann die Linie nur gerade von oben nach unten verlaufen.
TLineAlign = (
laLeft, // links anliegend laRight, // rechts anliegend laTop, // oben anliegend laBottom, // unten anliegen laDiagUp, // diagonal "abwärts" laDiagDown // diagonal "aufwärts" ) Der x-Offset beträgt dann 0.5 * Linienbreite. Bei laTop und laBottom kann die Linie nur waagerecht verlaufen. Der y-Offset beträgt dann 0.5 * Linienbreite. Bei laDiagUp und laDiagDown läuft die Linie von Ecke zu Ecke. Dein Beispiel wäre laDiagDown weil die Linie von links oben nach rechts unten verläuft. Bei den diagonalen Linien muss man die Endpunkte der Linie jeweils in x- und y-Richtung um die halbe Linienbreite verschieben. Es ist sinnvoll sich diese 6 Fälle grafisch aufzuzeichnen (so wie du das im Anhang schon für einen Fall gemacht hast).
Delphi-Quellcode:
procedure CalcOffsets(la:TLineAlign; Linewidth:integer; var offsetX, offsetY:Integer);
begin offsetX = 0; offsetY = 0; case la of laLeft : offsetX := Linewidth div 2; laRight: offsetX := -(Linewidth div 2); laTop : offsetY := Linewidth div 2; laBottom : offsetY := -(Linewidth div 2); laDiagUp, laDiagDown : begin offsetX := Linewidth div 2; offsetY := Linewidth div 2; end; end; end; |
AW: TLine - Canvas an Line ausrichten
Ja, das ist klar (Siehe OffSet1 und OffSet2). Typen hab ich auch schon (hab ich in der Paint jetzt weggelassen).
Delphi-Quellcode:
Das Problem ist aber ein anderes. Ich mu0 hier genau zeichen. Ich will ja eine Line von z.B. P1 nach P2 haben und nicht von P1 + Offset nach P2 - Offset?
TLineStyle = (lsTop, lsBottom, lsLeft, lsRight,
lsTopLeft, lsTopRight, lsBottomLeft, lsBottomRight, lsTopLeftBottomRight, lsTopRightBottomLeft); procedure TLine.Paint; var X1, Y1, X2, Y2: Integer; begin with Canvas do begin Pen := FPen; X1 := 0; Y1 := 0; X2 := Width; Y2 := Height; if X2 < 0 then begin Dec(X1, OffSet2); Inc(X2, OffSet1); end else begin Inc(X1, OffSet1); Dec(X2, OffSet2); end; if Y2 < 0 then begin Dec(Y1, OffSet2); Inc(Y2, OffSet1); end else begin Inc(Y1, OffSet1); Dec(Y2, OffSet2); end; case FStyle of lsTop, lsLeft, lsTopRight, lsBottomLeft, lsTopLeftBottomRight: MoveTo(X1, Y1); lsRight, lsTopLeft, lsBottomRight, lsTopRightBottomLeft: MoveTo(X2, Y1); lsBottom: MoveTo(X1, Y2); end; case FStyle of lsTopLeft: LineTo(X1, Y1); lsTopRight: LineTo(X2, Y1); lsBottomLeft: LineTo(X1, Y2); lsBottomRight: LineTo(X2, Y2); end; case FStyle of lsTop: LineTo(X2, Y1); lsLeft, lsTopLeft, lsBottomRight, lsTopRightBottomLeft: LineTo(X1, Y2); lsBottom, lsRight, lsTopRight, lsBottomLeft, lsTopLeftBottomRight: LineTo(X2, Y2); end; end; end; |
AW: TLine - Canvas an Line ausrichten
Liste der Anhänge anzeigen (Anzahl: 1)
Vielleicht nochmal zur Erläuterung. Man gibt die roten Koordinaten (Siehe 2. Anlage) vor und die Komponente wird dann so dargestellt (möglichst schon zur Designzeit auf der Form, Offset nach außen, also so wie MoveTo/LineTo das eigentlich machen würde). Das krieg ich aber nicht hin? :gruebel:
|
AW: TLine - Canvas an Line ausrichten
Zitat:
Das Rechteck, dass von der Komponente mit Top, Left, Height und Width aufgespannt wird, darf auf keinen Fall überschritten werden. (das blaue Rechteck) Die beiden Endpunkte einer Linie spannen ebenfalls ein Rechteck auf. (das rote Rechteck) Dieses Rechteck muss bei diagonalen Linien jeweils um die halbe Linienbreite kleiner sein als das umgebende Rechteck der Komponente. Du könntest der Komponente eine Methode spendieren, die das Rechteck der Komponente entsprechend vergrössert:
Delphi-Quellcode:
procedure TLine.InflateBoundingRect;
var lw2 : integer; begin lw2 := LineWidth div 2; // TODO: Fallunterscheidung bzgl. TLineAline bzw.TLineStyle SetBounds(Left-lw2, Top-lw2, Width+lw2, Height+lw2); end; |
AW: TLine - Canvas an Line ausrichten
Zitat:
Zitat:
|
AW: TLine - Canvas an Line ausrichten
Nee, das geht nicht. Wo sollte ich das auch hinschreiben? In Paint geht ja nicht. Da würde ja bei jedem Paint With und Height der Komponente vergrößert. Width und Height sind ja die von TGraphicControl geerbten. Deshalb meinte ich, man sollte die Komponente vielleicht von was ganz anderem ableiten, nur von welcher? wobei ich die Mauseereignisse schon bräuchte..
|
AW: TLine - Canvas an Line ausrichten
Was mir gestern abend noch eingefallen ist, was ich brauch' nennt man wohl Autosize.
Deshalb schau ich mir gerade die TCustomLabel an, weil die auch von TGraphicControl ebgeleitet ist und ein Autosize hat (die Komponentenhöhe wird da ja auch anhand der Fontgröße gesetzt, falls Autosize true ist). In diesem Zusammenhang ist bei mir folgende Frage aufgetaucht:
Delphi-Quellcode:
Die beiden Properties. Diese Syntax ist mir nicht bekannt.
TCustomLabel = class(TGraphicControl)
.. public .. property Caption; property Canvas; end; Wieso weiß denn Delphi, von welchem Typ die sind? |
AW: TLine - Canvas an Line ausrichten
Die Property ist in TControl als protected implementiert und wird in TCustomLabel sichtbar gesetzt (public)
TCustomLabel/TGraphicControl/TControl |
AW: TLine - Canvas an Line ausrichten
Ok. Thanx.
Die Methode Loaded war mir auch nicht bekannt. Es geht so, wie sx2008 vorgeschlagen hat. Hab aber nicht gewußt, daß das nach Loaded rein muß. Was aber immer noch nicht geht, daß es zur Designzeit angezeigt wird. :gruebel:
Delphi-Quellcode:
procedure TLine.Loaded;
begin inherited Loaded; AdjustBounds; end; |
AW: TLine - Canvas an Line ausrichten
Ich würde der Komponente eigene Propertys zuweisen:
X1, Y1 ... für Point1 X2, Y2 ... für Point2 LW ... für Linienbreite LA für LineAlign Dann kannst Du Left, Top, With und Height die Komponente selbst berechnen lassen (veranlasst durch die Setter der neuen Propertys): Left := Min(X1, X2) - (LW div 2); Top := Min(Y1, Y2) - (LW div 2); Width := Max(X1, X2) - Min(X1, X2) + (LW div 2); Height := Max(Y1, Y2) - Min(Y1, Y2) + (LW div 2); (so ins unreine...) |
AW: TLine - Canvas an Line ausrichten
Ja Stahli, das ist für hier wirklich sehr sehr viel einfacher. Dann wird zur Designzeit auch gleich alles richtig angezeigt. :thumb::thumb::thumb:
Das einzige was ich jetzt noch hab ist: Width und Height sind ja vom UrUrVorfahren. Wie kriegt denn meine Komponete mit, daß die sich geändert haben. Ich muß ja dann X1/Y1 und X2/Y2 entsprechend anpassen?
Delphi-Quellcode:
procedure TLine.SetX1(const Value: integer);
begin FX1 := Value; Left := FX1 - OffSet; end; procedure TLine.SetX2(const Value: integer); begin FX2 := Value; Width := FX2 - FX1 + OffSet + OffSet; end; procedure TLine.SetY1(const Value: integer); begin FY1 := Value; Top := FY1 - OffSet; end; procedure TLine.SetY2(const Value: integer); begin FY2 := Value; Height := FY2 - FY1 + OffSet + OffSet; end; function TLine.OffSet: integer; begin Result := FPen.Width div 2; end; |
AW: TLine - Canvas an Line ausrichten
Die Setter dürften virtuell sein, aber ich würde einfach Resize überschreiben (und prüfen, ob die Änderung von deinen neuen Eigenschaften kommt oder nicht).
|
AW: TLine - Canvas an Line ausrichten
Zitat:
Zitat:
|
AW: TLine - Canvas an Line ausrichten
Flag. ;-)
|
AW: TLine - Canvas an Line ausrichten
Ich habs soweit fertig. Was ich bissl blöd find, daß wenn man z.B. eine Line von 0,0 nach 1000,1000 zeichnet, das Width und Height der Komponente sehr groß werden. Auch schlecht für MouseEnter, MoueLeave, MouseMove usw.. Besser fände ich es, wenn man das Canvas um die Line herum bauen könnte (schräges Rect). Man bräuchte dann auch kein LineAlign mehr. Wie macht denn sowas? Muß man dann erst mal was TControl ableiten und ein eignes Canvas hineinfriemeln?
|
AW: TLine - Canvas an Line ausrichten
So funktionieren Komponenten nicht. Wenn Du nur eines Deiner Lineshapes benötigst kannst Du eigene Events einbauen die im Mousemove auf Kollision mit Deiner Linie prüfen. Da ich aber davon ausgehe dass Du mehrere benötigen wirst, ist allein durch die Überlagerung der Komponenten damit Schluss. Bei Wincontrols könnte man sich durch das definieren von Regions eine Weile über Wasser halten. Letztendlich wird es IMHO aber eher auf eine Komponente hinauslaufen die beliebig viele "Objekte" wie Linien/Kreise etc. darstellen und verwalten kann und die Kollisionsprüfung im MouseMove über die Objektdefinitionen vornimmt.
|
AW: TLine - Canvas an Line ausrichten
Bummi, du hast ja sowas von Recht!! Dieses ewige BringToFront SendToBack hab ich überhaupt nicht bedacht. Das kann ich unmöglich bringen. Damit ist dieses Konzept letztlich gestorben.
Offengestanden waren mir Shapes eh viel zu langsam. Und jetzt auch von TWInControl ableiten und Regionen zuweisen? Ich werd ganz klassisch eine ScrollBox nehemen und eine Paintbox rein. Eine Objectlist muß intern eh mitlaufen, dann kann ich auch jedem Object eine Region zuweisen. Sollten mehrere Regionen gefunden werden, kann man die Elemente ja vorher in einem PopUp zur Auswahl stellen. Gruß Thomas |
AW: TLine - Canvas an Line ausrichten
Liste der Anhänge anzeigen (Anzahl: 1)
Hat zwar nicht direkt mit Pfeilen zu tun, ist aber auch nur eine Komponente ....
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 06:09 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz