Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   GUI-Design mit VCL / FireMonkey / Common Controls (https://www.delphipraxis.net/18-gui-design-mit-vcl-firemonkey-common-controls/)
-   -   Delphi Linien Komponente (https://www.delphipraxis.net/77174-linien-komponente.html)

halinchen 15. Sep 2006 16:22


Linien Komponente
 
Hi!

Ich hab mal wieder ein Problem:
Ich suche ein Linien-Komponente. Im Internet hab ich gefunden das man die am besten selber macht und von TShapes ableitet.
Ich hab sowas aber noch nie gemacht und weiß nicht wie's geht. :?:

Ich bräuchte das so:
x1,y1,x2,y2 als Punkte und dazwischen eine Linie (vielleicht noch mit Breiten-änderung).
(Wie das mit der Linie geht weiß ich auch nicht)

Ich brauch sozugen nur ein Starthilfe. :)

Achso wenn es sowas schon gibt dann brauch ich das nicht selber programmieren. Aber ich hab schonmal geguckt und nichts gefunden.)

Der_Unwissende 15. Sep 2006 16:35

Re: Linien Komponente
 
Hi,
was genau verstehst du denn unter einer Linien Komponente?
Also am einfachsten ist es, wenn du die Linie selbst zeichnest. Dazu brauchst du einen Canvas, das ist die Zeichenfläche. So ein Canvas ist etwas, was du nie direkt selbst erzeugst, du verwendest vielmehr immer einen, der dir zur Verfügung gestellt wird. Typsiche Beispiele sind hier alle Fenster von Windows. Die Zeichenroutine bekommt einfach deren Canvas übergeben und die zeichnet dann darauf. Das was die zeichnet ist dann das, was du siehst.
Auch dein Formular hat einen Canvas. Auf den könntest du direkt zeichnen (was aber nicht so wirklich schön ist).

Am einfachsten kannst du selbst zeichnen, wenn du eine Bitmap verwendest. TBitmap kapselt alles was du brauchst, da gibt es dann sogar schon eine Funktion für das was du vor hast:
Delphi-Quellcode:
procedure drawLine(const x1, y1, x2, y2 : Integer);
var bitmap : TBitmap;
begin
  bitmap := TBitmap.Create;
  // wichtig Größe setzen
  bitmap.Width := xxx;
  bitmap.Height := xxx;
 
  // das eigentliche Zeichnen
  bitmap.Canvas.MoveTo(x1, y1);
  bitmap.Canvas.LineTo(x2, y2);
 
  bitmap.Free;
end;
Ok, hier fehlt natürlich als erstes mal die Größe der Bitmap. Da musst du schauen, welche Größe du brauchst. Dann fehlt auch noch das Anzeigen. Der einfachste Weg ist, dass du ein TImage nimmst. Um hier ein Bitmap anzuzeigen musst du (vor dem Bitmap.Free) der Eigenschaft Image.Picture das Bitmap zuweisen.

Gruß Der Unwissende

oki 15. Sep 2006 16:52

Re: Linien Komponente
 
Hi Unwissender (da war er wieder :stupid: )

warum redest du immer von Bitmap und Image. Halinchen will doch nur eine Linie.

Ich dächte TBevel währe da doch schon mal was.

wenn die Linie dann noch was anderes können muß außer eine Linie zu sein, dann können wir ja noch mal schauen. :stupid:

gruß oki

Der_Unwissende 15. Sep 2006 19:14

Re: Linien Komponente
 
Hi Oki,
ja hast schon recht, ich dachte nur wenn man zwei x,y Tupel angibt, dann doch eigentlich weil man nicht langweilig gerade Linien möchte (also senkrecht zu den Seiten des Fensters).
Ansonsten fehlt (soweit ich weiß) dem TBevel die Möglichkeit die Dicke der Linie zu verändern. Bei einem Canvas gibt es einen Strift, mit dem die Linie gezeichnet wird (Eigenschaft Pen des Canvas), dieser hat dann eine Farbe und eine Dicke.
Für Shapes gibt es einen ähnlichen Grund, aus dem ich sie ausgeschlossen hatte. Einem TShape fehlt die Linie (oder irre ich mich auch da?).

Gruß Der Unwissende

halinchen 16. Sep 2006 11:22

Re: Linien Komponente
 
Erstmal danke für die Antworten!

Mit Canvas kenn ich mich nicht so aus, aber ich wollte die Linie zur Laufzeit immer wieder wo anders hinsetzen und länger oder kürzer machen. Außerdem sollte die Linie auch diagonal sein können.

Das geht zwar alles mit Canvas, aber ich hätte das lieber als Object, da ich mich da besser auskenne.

Bevel und Shape-Control können nicht diagonal sein. (Wenn man Shape auf Rechteck setzt und Height auf 1 setzt hat man waagerechte Linie, aber keine diagonale.)

mkinzler 16. Sep 2006 11:25

Re: Linien Komponente
 
Ein Canvas ist doch auch ein Objekt. da man auf dem Canvae zeichen kann, ist diese Lösung doch flexibel. Es gibt verschiedene Komponenten, welche einen Canvas anbieten z.B. TImage, TPaintBox, ...

halinchen 17. Sep 2006 17:21

Re: Linien Komponente
 
Ich hab das alles nochmal überdacht. Es gibt eigentlich 1 gute Möglichkeiten.

Ich mache eine Komponente oder ein Objekt mit den vier Punkten als Property. Wenn die Propertys berabeitet werden mach ich eine Line dazwischen. Dann muss ich aber vorher refresh aufrufen, da sonst die alte Linie erhaltenbleibt. Die anderen Linien die die gezeichnet worden (Im falle von mehreren Variablen des Linien-Objekts) sind dann aber auch weg. Da scheib ich eine Prozedur die alle Linien Objekte durchgeht und die dann neuzeichnet.

Kann mir vielleicht jemand sagen wie das bei TShapes geht? Die werden ja automatisch neugezeichnet. Das könnte ich vielleicht bei mir einbauen.) :-D

mkinzler 17. Sep 2006 17:24

Re: Linien Komponente
 
Das mit einer festen Anzahl von Properties für die Punkte ist aber schlecht. Nimm lieber eine dynamische Anzahl von Punkten so kannst du statt Linien auch komplexere Linienzüge zeichen ( Polyline, Polygone)

oki 18. Sep 2006 07:35

Re: Linien Komponente
 
Hi hallinche,

klar, bei diagonalen Linien ist es natürlich vorbei mit den Bevels. Also mußt du dir wirklich ein geeignetes Basisobjekt suchen und deine eigenen Zeichenroutinen schreiben. Achte aber darauf, das es von TComponent abgeleitet ist. Dann nehme z.B. bei einem Panel nicht TPanel, sondern TCustomPanel...

Als nächstes würde ich erst mal genau sortieren, was du mit deiner neuen Komponente alles machen möchtest. Diese Idee ist nicht schlecht:
Zitat:

Zitat von mkinzler
Das mit einer festen Anzahl von Properties für die Punkte ist aber schlecht. Nimm lieber eine dynamische Anzahl von Punkten so kannst du statt Linien auch komplexere Linienzüge zeichen ( Polyline, Polygone)

wird aber bedeutend komplexer.

das automatische Zeichnen ist nicht weiter schlimm. Hier vererbst du die Paint-Methode via override und implementierst deine eigene Zeichenmethode.

Delphi-Quellcode:
procedure TMyObject.Paint;
begin
  inherited;
  MyPaint;
end;
In MyPaint schreibst du alles was du für dein Zeichen brauchst.


gruß oki

halinchen 18. Sep 2006 15:37

Re: Linien Komponente
 
Das klingt gut, da weiß ich jetzt was ich machen muss.
:-D

Danke für die vielen Antworten. :party:

halinchen 19. Sep 2006 18:26

Re: Linien Komponente
 
Hi!
Das hab ich jetzt im Quelltext stehen. (Hab mich erstmal nur für die einfache Linie entschieden.)

Delphi-Quellcode:
unit Line;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs;

type
  TLine = class(TComponent)
  private
    A,E:TPoint; //Anfang+Ende
    W:Integer; //Width
    C:TColor; //Color
    Can:TCanvas; /Canvas
    { Private-Deklarationen }
  protected
    { Protected-Deklarationen }
  public
    procedure Draw;
    { Public-Deklarationen }
  published
    property X1:Integer read A.X write A.X;
    property X2:Integer read A.Y write A.Y;
    property Y1:Integer read E.X write e.X;
    property Y2:Integer read E.Y write E.Y;
    property Witdth:integer read W write W;
    property Color:TColor read C write C;
    property Canvas:TCanvas read Can write Can;
    { Published-Deklarationen }
  end;

procedure Register;

implementation


procedure Tline.Draw;
begin
Can.PenPos := A;
Can.Pen.Width := W;
Can.Pen.Color := C;
Can.LineTo(E.X,E.Y);
end;

procedure Register;
begin
  RegisterComponents('Zusätzlich', [TLine]);
end;

end.
Meine Fragen:
1. Can := Form1.Canvas; geht nicht. (Geht schon aber da ist das ja kein Verweis auf Form1.Canvas sondern nur eine Wertübergabe. Und ich möchte einen Verwies.

2.Wie mach ich ein Ereignis? Im meinem Buch steht:

type TEreignis = procedure (Sender: TComponent;var I: Integer) of object;

und dann in der Klasse:

Delphi-Quellcode:
private
FEreignis: TEreignis;
published
property OnEreignis: TEreignis read FEreignis write FEreignis;
Aber wie mach ich, dass das Programm OnEreignis aufruft, wenn irgentwas passiert ist (überzeichnet, geklickt)?

Sunlight7 19. Sep 2006 19:03

Re: Linien Komponente
 
1. Du kannst auf das Canvas der Form zugreifen mit

Delphi-Quellcode:
If Assigned(AOwner) then
   if (AOwner is TForm) then
      TForm(AOwner).Canvas.LineTo ...

// Besser wäre noch statt TForm TWinControl zu verwenden.

If Assigned(AOwner) then
   if (AOwner is TWinControl) then
      TWinControl(AOwner).Canvas.LineTo ...
2. Dort wo das Ereignis ausgelöst werden soll

Delphi-Quellcode:
If Assigned(FEreignis) then
   FEreignis;

// Besser statt TEreignis TNotifyEvent
// Dann aber
If Assigned(FEreignis) then
   FEreignis(Self);

// Damit kannst Du im OnEreignis abfragen (Sender) welche Komponente das Ereignis ausgelöst hat.
// z.B. If Sender=LineControl2 then TueIrgendwas;

oki 20. Sep 2006 07:47

Re: Linien Komponente
 
Hi halinchen,

@ Sunlight7: Vorsicht, TWincontrol besitzt keinen Canvas. Der ist erst ab TCustomcontrol dabei.

@ Halinchen:

Ich würde an deiner Stelle nicht auf dem Canvas des Parents malen. Sicher ist das Ansichtssache, aber mit einer visuellen Componente ist das Platzieren meiner Meinung nach einfacher. Somit würde ich die Kompo folgendermaßen aufbauen:

Delphi-Quellcode:
unit Line;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs;

type
  TLine = class(TCustomControl)
  private
    A,E:TPoint; //Anfang+Ende
    W:Integer; //Width
    C:TColor; //Color
    Can:TCanvas; //Canvas
    { Private-Deklarationen }
  protected
    { Protected-Deklarationen }
    procedure Draw;
    procedure Paint; override;
  public
    { Public-Deklarationen }
  published
    property X1:Integer read A.X write A.X;
    property X2:Integer read A.Y write A.Y;
    property Y1:Integer read E.X write e.X;
    property Y2:Integer read E.Y write E.Y;
    property Witdth:integer read W write W;
    property Color:TColor read C write C;
    property Canvas:TCanvas read Can write Can;
    { Published-Deklarationen }
  end;

procedure Register;

implementation


procedure Tline.Draw;
begin
  self.canvas.PenPos := A;
  self.canvas.Pen.Width := W;
  self.canvas.Pen.Color := C;
  self.canvas.LineTo(E.X,E.Y);
end;

procedure Register;
begin
  RegisterComponents('Zusätzlich', [TLine]);
end;

procedure TLine.Paint;
begin
  inherited;
  Draw;
end;

end.
o.k., jetzt gibt das natürlich wenig Sinn mit den Koordinaten. so lange du hier keine Polygone zeichen möchtest, die du in einer Funktion abbilden kannst, reicht es hier eine Eigenschaft für die Linienart aufzunehmen. In einer visuellen Kompo nimmst du als koordinaten dann die entsprechenden eigenen Dimensionen wie self.left usw.

Bsp.:
Delphi-Quellcode:
type
  TLineType = (ltNone,        // keine Linie
               ltLeft,        // Linie links
               ltRight,       // Linie rechts
               ltTop,         // Linie oben
               ltBottom,      // Linie unten
               ltVCenter,     // Mitte vertikal
               ltHCenter      // Mitte horizontal
               );
Hier kannst du dann auch noch weitere typen aufnehmen wie Diagonalen usw.

weitere Eigenschaften für Linienenden (Pfeile, kreise ...) kannst du natürlich genauso einbinden. Diverse Graphikprogramme bitten da einen guten Überblick über probate Linieneigenschaften (vorallem vektor orientierte wie CorelDraw usw.).

In deiner Draw Methode kannst du dann mit Case of in die entsprechenden Zeichenmethoden verzweigen.

Gruß oki

Sunlight7 20. Sep 2006 20:06

Re: Linien Komponente
 
@oki

Danke für den Hinweis.

Eigentlich sollte ich das ja Wissen, aber auch nach 10 Jahren falle ich immer wieder auf TWinControl rein :oops:


Alle Zeitangaben in WEZ +1. Es ist jetzt 14:43 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