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/)
-   -   Kreis/Linie zwischen 2 TButtons (https://www.delphipraxis.net/205678-kreis-linie-zwischen-2-tbuttons.html)

Schwedenbitter 5. Okt 2020 13:10

Kreis/Linie zwischen 2 TButtons
 
Hallo,

ich brauche beruflich immer mal wieder Stammbäume.

Zu diesem Zweck habe ich mir ein Control
Delphi-Quellcode:
TPerson
gebastelt, abgeleitet von
Delphi-Quellcode:
TBitBtn
. Darin sind zur Laufzeit jeweils die Personendaten enthalten. Diese Personen/Buttons kann ich wiederum in einer
Delphi-Quellcode:
TScrollBox
mit der Maus frei verschieben. Vielleicht ginge das eleganter. Aber als Hobbyprogrammierer fiel mir nichts besseres ein.
Ich habe den Code nun nach Jahren mal wieder vorgekramt.

Mein Ziel wäre es jetzt, zwischen den Buttons in Abhängigkeit der Verwandtschaft Linien zu ziehen. Zwischen 2 Verheirateten TPersons hätte ich gern einen Kreis.

Jetzt haben ich schon folgenden Code entdeckt, womit das grundsätzlich klappt:
Delphi-Quellcode:
procedure TForm1.FormPaint(Sender: TObject);
begin
   Canvas.Pen.Style:= psSolid;
   Canvas.Pen.Color:= clBlue;
   Canvas.Pen.Width:= 1;

   Canvas.MoveTo(Button1.Left + (Button1.Width div 2),
                 Button1.Top + (Button1.Height div 2));
   Canvas.LineTo(Button2.Left + (Button2.Width div 2),
                 Button2.Top + (Button2.Height div 2));
end;
Allerdings muss ich auf Änderungen reagieren. Soll heißen:
Wenn eine TPerson verschoben wird, muss die alte Linie/der alte Kreis weg und eine neue gemalt werden (auch hier).

Gibt es da Möglichkeiten/Ideen, ohne dass ich meinen Code vollständig neu programmieren muss?

Gruß, Alex

TiGü 5. Okt 2020 16:07

AW: Kreis/Linie zwischen 2 TButtons
 
Wenn du es beruflich brauchst, wäre hier die Wahl eines professionellen Familienforschungsprogramms nicht besser?

Beispiel:
https://www.ahnenblatt.de

Schwedenbitter 6. Okt 2020 06:41

AW: Kreis/Linie zwischen 2 TButtons
 
Liste der Anhänge anzeigen (Anzahl: 1)
Nein. Leider nicht.

Denn das Beispiel Ahnenblatt kann nicht "ahnnähernd" das, was ich brauche.
Auf der anderen Seite ist es viel zu umfangreich. Und die Bedienung ist viel zu kompliziert. Es geht z.B. grundsätzlich von einer Familie Mutter, Vater, Kinder aus. Wenn ich mehrere "Eltern" durch Scheidung/Heirat habe, gibt es schon Probleme. Der Baum ist - sowie ich das noch in Erinnerung habe - nicht frei drehbar. Er wird von unten nach oben aufgebaut - vom Kind zu den Eltern, es sollen ja die "Ahnen" erforscht werden. Ich brauche es genau umgekehrt.
etc. pp.

Ich würde mir nie die Mühe machen, etwas zu programmieren, wenn es das schon genau so gäbe, wie ich es brauche.

[edit]Ich habe mal angehängt, was ich schon habe.[/edit]

bcvs 6. Okt 2020 06:51

AW: Kreis/Linie zwischen 2 TButtons
 
Zitat:

Zitat von Schwedenbitter (Beitrag 1474885)
Allerdings muss ich auf Änderungen reagieren. Soll heißen:
Wenn eine TPerson verschoben wird, muss die alte Linie/der alte Kreis weg und eine neue gemalt werden

Und wo ist jetzt genau das Problem? Soll die Verbindungslinie beim Verschieben ständig mitgeführt werden, oder reicht es, wenn sie nach dem Verschiebevorgang neu gezeichnet wird?

stahli 6. Okt 2020 07:43

AW: Kreis/Linie zwischen 2 TButtons
 
Es gibt verschiedene Ansatzmöglichkeiten.

Was zu empfehlen ist hängt davon ab, wie erfahren Du in den einzelnen Themenbereichen bist.

Man könnte mit VCL-Controls arbeiten, diese anordnen und nur auf deren Canvas zeichnen.
Man könnte die Objekte als VCL-Controls aufbauen und die Verbindungen auf das Formular malen.
Oder man könnte alles auf einen Canvas malen und die Positionen virtuell merken und sozusagen bei einem Klick auf das Formular ermitteln, welches "virtuelle Control" wohl gemeint war.

Ich habe alles schon gemacht.

Wenn Du willst, schau mal meine Turniersoftware und dort das KO-System an. Da sind die Verbindungen mit Teil der Spiele.
Die Raster der Designer sind dagegen in den Hintergrund gemalt.

Den dritten Ansatz habe ich hier angewendet:
https://www.delphipraxis.net/175033-...chlecht-2.html (#59 und #60)
und hier: https://www.delphipraxis.net/185623-...-controls.html


Vielleicht hilft Dir das bei grundsätzlichen Überlegungen.
Im Detail bleibt da natürlich noch vieles zu überlegen...

mkinzler 6. Okt 2020 08:53

AW: Kreis/Linie zwischen 2 TButtons
 
Oder man verwendetet Komponenten für Diagramme.

Schwedenbitter 6. Okt 2020 10:45

AW: Kreis/Linie zwischen 2 TButtons
 
Danke erstmal für die zahlreichen Tipps!

Zitat:

Zitat von stahli (Beitrag 1474938)
...
Man könnte mit VCL-Controls arbeiten, diese anordnen und nur auf deren Canvas zeichnen.

Wenn ich das richtig verstehe also zwischen meine Buttons z.B. ein TImage packen, was sich mit bewegt und dann die Linien darin zieht?

Zitat:

Zitat von stahli (Beitrag 1474938)
Man könnte die Objekte als VCL-Controls aufbauen und die Verbindungen auf das Formular malen.

Das war meine ursprüngliche(r) Idee/Plan. Aber da habe ich das Problem der Reaktion auf ein Verschieben des Buttons. Wenn ein Button die Position ändert, muss ja die alte Linie weg und eine neue Linie gezeichnet werden :gruebel:

Zitat:

Zitat von stahli (Beitrag 1474938)
Oder man könnte alles auf einen Canvas malen und die Positionen virtuell merken und sozusagen bei einem Klick auf das Formular ermitteln, welches "virtuelle Control" wohl gemeint war.

Das übersteigt mit Sicherheit meine Fähigkeiten. Außerdem müsste ich dann komplett neu anfangen, weil ich die frei verschiebbaren Buttons ja schon habe.
Für mich ist mein Programm an sich perfekt - nur die Linien fehlen.

Zitat:

Zitat von stahli (Beitrag 1474938)
Wenn Du willst, schau mal meine Turniersoftware und dort das KO-System an...
Die Raster der Designer sind dagegen in den Hintergrund gemalt.

Dieser Designer sieht ziemlich genau nach dem aus, was mir so vorschwebt.

Ich habe mir auch ein paar der verlinkten youtube-Videos angeschaut. Gibt es da irgendwo Code-Beispiele?
Das entspricht so ziemlich genau dem, was ich mir vorstelle. Die CPU-Last ist mir dabei nahezu egal. Selbst bei umfangreichen Bäumen komme ich so auf ca. 40 "Mitspieler". Und häufig wird das Bild nur einmal gebastelt und danach immer nur zum Anschauen/Drucken geladen.

stahli 6. Okt 2020 13:14

AW: Kreis/Linie zwischen 2 TButtons
 
Deine erste Frage zu den Images zwischen den Buttons: Ja.

Es ist halt die Frage, was Du anklicken, verschieben und in den Größen ändern willst.
Danach musst Du entscheiden, ob Du Controls brauchst, die auf Mausereignisse reagieren können oder nicht.

Dann ist auch die Frage, wie komplex die Linien, Kreise und andere Figuren so werden können.
Wenn Du z.B. einen Kreis hast und der sich neu zeichnet, wenn Du die Größe des Images änderst, ist das komfortabel.
In anderen Fällen, wenn Du z.B. eine längere Verbindungslinie über verschiedene Verwinkelungen zeichnen willst, ist ein Image vielleicht schlecht geeignet.

Wenn Du nur Deine Buttons anklicken und schieben willst, dann würde ich die Figuren drum herum auf den Hintergrund malen. Dann kannst Du den Canvas auch gleich nutzen, um ein Bitmap für die Wiederverwendung zu speichern.

Meinen Code könnte ich Dir geben aber das würde Dir wohl nicht viel helfen, fürchte ich. War ein ziemlich komplexes Projekt mit eigenem Framework usw.

Schwedenbitter 6. Okt 2020 13:32

AW: Kreis/Linie zwischen 2 TButtons
 
Liste der Anhänge anzeigen (Anzahl: 2)
Die Idee mit dem Code ist total nett, würde mich aber wohl wirklich überfordern.

Ich habe mal quick & dirty etwas zusammengebastelt. Daran kann man sehen, wo ich gern hin käme. Bevor ich mich z.B. um das weitere Problem
Delphi-Quellcode:
Button2
vor/über
Delphi-Quellcode:
Button1
kümmere, hätte ich dazu mal 2 Fragen:
  1. Wie bekomme ich das Bild - abgesehen von der Linie - transparent?
  2. Gibt es eine Möglichkeit, die Linie schon während des Verschiebens nachzeichnen zu lassen?

Für "Downloadmuffel" hier mal der Code:
Delphi-Quellcode:
Procedure TForm1.Button2MouseDown(Sender: TObject; Button: TMouseButton;
   Shift: TShiftState; X, Y: Integer);
Const
   SC_DRAGMOVE      = $F012;
Begin
   If (ssLeft in Shift) Then                        // nur bei linker Maustaste
   Begin
      ReleaseCapture;                              // Freigeben der Maus
      Button2.Perform(WM_SYSCOMMAND, SC_DRAGMOVE, 0);   // Ziehen = Bewegen

      Image1.Picture.Assign(nil);                  // Bild löschen
      Image1.Transparent:= True;                  // ==> Funktioniert schon einmal NICHT!
      Image1.Left:=  Button1.Left + (Button1.Width div 2);
      Image1.Top:=   Button1.Top + (Button1.Height div 2);
      Image1.Width:= Button2.Left -  Button1.Left;
      Image1.Height:= Button2.Top -  Button1.Top;

      Image1.Canvas.Pen.Style:= psSolid;
      Image1.Canvas.Pen.Color:= clBlue;
      Image1.Canvas.Pen.Width:= 5;
      Image1.Canvas.MoveTo(0, 0);                     // wohin auch sonst
      Image1.Canvas.LineTo(Image1.Width, Image1.Height);
   End;
End;

TurboMagic 6. Okt 2020 17:31

AW: Kreis/Linie zwischen 2 TButtons
 
Probier mal das:

Image1.Picture.Bitmap.TransparentColor := clWhite;

stahli 6. Okt 2020 20:52

AW: Kreis/Linie zwischen 2 TButtons
 
Willst Du die Linien irgendwie mit der Maus beeinflussen können?

Wie viele Möglichkeiten der Verbindungen gibt es?
- LinieLinksUntenNachRechtsOben
- LinieRechtsUntenNachLinksOben
- Vollkreis
- LeererKreis

Wenn Du eine begrenzte Anzahl hast, könnte man mit einer Image überlegen.
Dann kannst Du den Status (Linienart) zuweisen, die Größe festlegen und die Linien werden passend gezeichnet.

Wenn die Anzahl der Linien oder Figuren sehr groß werden kann oder die Linien nicht auf die Maus reagieren müssen, dann würde ich eher die Buttons anordnen, die Linien in ein Bitmap zeichnen und dieses auf den Canvas des Formulars kopieren.

v2afrank 7. Okt 2020 05:54

AW: Kreis/Linie zwischen 2 TButtons
 
Liste der Anhänge anzeigen (Anzahl: 1)
Auch wenn es wahrscheinlich nicht hilft möchte ich die Jedis mit Ihren Diagramshapes nicht unerwähnt lassen. Schau Dir mal die Demos an.
Damit habe ich das folgende Bild realisiert

Schwedenbitter 7. Okt 2020 07:15

AW: Kreis/Linie zwischen 2 TButtons
 
Liste der Anhänge anzeigen (Anzahl: 3)
Zitat:

Zitat von stahli (Beitrag 1474980)
Willst Du die Linien irgendwie mit der Maus beeinflussen können?

Nein - wird vermutlich auch nie nötig werden.

Zitat:

Zitat von stahli (Beitrag 1474980)
Wie viele Möglichkeiten der Verbindungen gibt es?
- LinieLinksUntenNachRechtsOben
- LinieRechtsUntenNachLinksOben

Ich habe mal weiter probiert. Vom Grundsatz her scheine ich mit den Linien klarzukommen (Screenshot). Da ein Kind i.d.R. nicht von mehr als 2 Eltern abstammt, sind es maximal 2 Verbindungen; eher nur eine.

DENN:
Zitat:

Zitat von stahli (Beitrag 1474980)
- Vollkreis
- LeererKreis

Der Kreis steht als Symbol für eine Ehe/Beziehung etc. Daher eben nur eine Verbindung des Kindes zu diesem Kreis (Screenshot - wo ich gern hin will). Beim Kreis komme ich wohl an einem anderen TObject nicht vorbei. Sonst wird wohl die Rechnerei zwischen Kreis und Linien zu umfangreich.

Zitat:

Zitat von stahli (Beitrag 1474980)
...
Dann kannst Du den Status (Linienart) zuweisen, die Größe festlegen und die Linien werden passend gezeichnet.

Verstehe ich das richtig, dass die Linien dann "automatisch" angepasst/gezeichnet werden :gruebel:
Falls ja, gibt es da irgendwo Beispiele zu finden?

Zitat:

Zitat von stahli (Beitrag 1474980)
Wenn die Anzahl der Linien oder Figuren sehr groß werden kann oder die Linien nicht auf die Maus reagieren müssen, dann würde ich eher die Buttons anordnen, die Linien in ein Bitmap zeichnen und dieses auf den Canvas des Formulars kopieren.

Was spricht dagegen, wenn man die Linien gleich auf das Canvas malt, außer vielleicht, dass sie dann beim Verschieben mal kurz verschwinden?

P.S. Zu meinem 2. Screenshot mal die (Zusatz)Frage:
Wieso erscheinen die Linien nicht beim Programmstart? Meine Malroutine lasse ich jetzt sowohl bei
Delphi-Quellcode:
FormCreate
(da gibt es vermutlich die Buttons noch nicht) als auch bei
Delphi-Quellcode:
FormShow
aufrufen. Die Linien sehe ich aber immer erst, wenn ich einen Button bewege.

Schwedenbitter 7. Okt 2020 07:35

AW: Kreis/Linie zwischen 2 TButtons
 
Zitat:

Zitat von v2afrank (Beitrag 1474985)
... Jedis mit Ihren Diagramshapes ...

Danke für den Hinweis :thumb:

Im Moment will ich da aber aus mind. 2 Gründen nicht ran:

Zum einen habe ich mein Programm im Grunde fertig. Ich nutze es seit gut 3 Jahren. Die Linien male ich von Hand in exportierte png-Dateien hinein. Denn i.d.R. ändern sich die Stammbäume äußerst selten. Mein neuer Ansatz ist also eher akademischer Natur und damit ich das Programmieren nicht verlerne und weil ich wissen will, ob ich es irgendwie hinbekomme :lol:
Zum anderen hatte ich mit den Jedis noch nie wirklich zu tun. Ich kenne sie und ich hatte dort wegen anderer Sachen reingeschaut (IP-Datentransfer etc.). Allerdings vermute ich, dass ich mich ewig einarbeiten muss, um annähernd so ein tolles Schaltdiagramm hinzubekommen. Und ich bin mir noch nicht einmal sicher, ob die Jedis am Ende flexibel genug für meine "Kinderzeichnungen" wären.

Schwedenbitter 7. Okt 2020 08:40

AW: Kreis/Linie zwischen 2 TButtons
 
:oops: ganz so einfach wird es wohl nicht werden.

Ich habe gerade versucht, mein kleines Beispiel rudimentär in mein Programm zu implementieren.
Dummer Weise liegen meine Personen (alias
Delphi-Quellcode:
TBitBtn
) in einer
Delphi-Quellcode:
TScrollBox
. Und wie ich feststellen musste, hat nun ausgerechnet diese kein
Delphi-Quellcode:
TCanvas
, auf das ich einfach mal eben malen könnte.
Meine Suche führte mich unter anderem zu diesem Beitrag. Und aus der fehlenden Antwort schließe ich nun, dass es keine (einfache) Lösung für dieses Problem gibt :wall:

Bevor ich weiter experimentiere:
Lege ich da einfach ein TImage in den Hintergrund und male auf dem?
Da habe ich aber wieder das Problem mit der nicht funktionierenden Transparenz.

Jumpy 7. Okt 2020 08:46

AW: Kreis/Linie zwischen 2 TButtons
 
Kann man nicht einfach ein Panel in die Scrollbox packen und die Buttons auf das Panel?

stahli 7. Okt 2020 09:26

AW: Kreis/Linie zwischen 2 TButtons
 
Zitat:

Zitat von Schwedenbitter (Beitrag 1474989)
Verstehe ich das richtig, dass die Linien dann "automatisch" angepasst/gezeichnet werden :gruebel:
Falls ja, gibt es da irgendwo Beispiele zu finden?

Ja, wenn Du die Verbindungen in eine grafische Komponente kapselst und die Art der Darstellung als Eigenschaft vorgibst.
Im Grunde genau wie ein TPanel oder TBevel.
Da hast Du z.B. eine Eigenschaft BevelOuter, die vorgibt, wie der Rahmen zu zeichnen ist.
Wenn Du die Komponente in der Größe änderst oder verschiebst, wird diese und das Formular entsprechend neu gezeichnet.

Du könntest also eine Komponente schreiben, die die Linien oder Kreise nach bestimmten Vorgaben immer gemäß der Komponentengröße passen zeichnet.


ABER:

Wenn man Dein Bild ansieht, wird das wohl eher nicht so günstig sein.
Du müsstest dann wohl mehrere Komponenten miteinander überlagern (Kreis, Linie1, Linie2, Linie3). Oder Du musst eine recht komplexe Komponente erstellen, die alle diese Figuren zusammen darstellt.
Dann wird es aber schwierig, wenn die Kinder in unterschiedlicher Höhe oder Winkel zu den Eltern ausgerichtet sind.


ALSO:

Ich würde die Verbindungen in den Hintergrund zeichnen.

Dafür könntest Du eine Panel und Paintbox oder Image nutzen, die Du in die Scrollbox legst. Auf das Panel dann auch Deine Buttons.
Dann brauchst Du Du Dich auch um das Scrollen usw nicht kümmern. Einfach nur die Größe des Panels einstellen und dann passt das.

Mit dem Erstellen der Linien in ein Bitmap und dann kopieren in den Canvas kann man Flackern verhindern, allerdings auch nur wenn man mit Threads arbeitet.
Zusätzlich hast Du die Verbindungen dann aber auch schon als Bild vorliegen, das Du dann ggf. leichter drucken kannst.

himitsu 7. Okt 2020 13:54

AW: Kreis/Linie zwischen 2 TButtons
 
Zitat:

Zitat von Schwedenbitter (Beitrag 1474989)
Wieso erscheinen die Linien nicht beim Programmstart? Meine Malroutine lasse ich jetzt sowohl bei
Delphi-Quellcode:
FormCreate
(da gibt es vermutlich die Buttons noch nicht) als auch bei
Delphi-Quellcode:
FormShow
aufrufen. Die Linien sehe ich aber immer erst, wenn ich einen Button bewege.

Weil das falsch ist?

In OnPaint

und bei Änderungen ein Repaint auslösen. (falls es durchs Verschieben der Buttons nicht schon passiert)


Alle Zeitangaben in WEZ +1. Es ist jetzt 16:25 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz