Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Seltsames Verhalten einer Funktion (https://www.delphipraxis.net/200467-seltsames-verhalten-einer-funktion.html)

Pytroxis 24. Apr 2019 11:34

Delphi-Version: 10.2 Tokyo

Seltsames Verhalten einer Funktion
 
Liste der Anhänge anzeigen (Anzahl: 2)
Hey,

ich bin es mal wieder, langsam verzweifle ich an Delphi :(

Bei meinem Programm werden Boxplots dargestellt/gezeichnet, prinzipiell funktioniert das auch.
Nun habe ich mich daran versucht 2 unterschiedliche Boxplots darzustellen und bin auf ein sehr großes Problem gestoßen:
Wenn beide Boxplots den gleichen Datensatz haben werden sie Normal dargestellt, sofern aber einer der Boxplots einen anderen Datensatz besitzt wird der erste nicht mehr korrekt dargestellt (siehe Anhang).
Ich habe bereits einiges getestet und bin zu folgendem Entschluss gekommen:
  • Es liegt nicht an dem sortieren /einlesen. Datensatz wird korrekt abgespeichert bzw. eingelesen und sortiert (-> Mehrfach überprüft).
  • Es muss an der Funktion für das zeichnen liegen
Ich habe die Funktion nun mehrfach neu geschrieben und auf Fehler überprüft aber ich finde einfach keinen (-> Bestimmt ein ganz simpler Fehler, den ich einfach nicht finde).

Dementsprechend hier die Funktion (bitte schlagt mich nicht für den schlechten Stil):
Delphi-Quellcode:
var
  zahlen : array of array of Double;
  namen : TStrings;
  quartils : array[0..1] of Double;
  median : Double;
  bereiche: array[0..3] of array of Double;

...

procedure drawLine(PaintBox:TPaintBox; color: TColor; minX, minY, maxX, maxY:integer);
 begin
  PaintBox.Canvas.Pen.Color := color;
  PaintBox.Canvas.MoveTo(minX, minY);
  PaintBox.Canvas.LineTo(maxX, maxY);
 end;

 procedure zeichnen(PaintBox : TPaintBox; Boxplot : real; FHeight, FWidth: Integer);
  var i, xWert, Height, index: integer;
      eineLaengeneinheit : Double;
      getHeight : array[0..9] of integer;


  begin
    if Length(zahlen) > 0 then begin
      xWert := 40;
      Height := round(FHeight * 0.4);
      index := Round(Boxplot);

      eineLaengeneinheit := (FWidth-120) / round(zahlen[index][Length(zahlen[index])-1] - zahlen[index][0]);


      getHeight[0] := round(FHeight * 0.31919 + Height * Boxplot);
      getHeight[1] := round(FHeight * 0.13214 + Height * Boxplot);
      getHeight[2] := round(FHeight * 0.18379 + Height * Boxplot);
      getHeight[3] := round(FHeight * 0.04839 + Height * Boxplot);
      getHeight[4] := round(FHeight * 0.09839 + Height * Boxplot);
      getHeight[5] := round(FHeight * 0.21839 + Height * Boxplot);
      getHeight[6] := round(FHeight * 0.15839 + Height * Boxplot);
      getHeight[7] := round(FHeight * 0.26839 + Height * Boxplot);
      getHeight[8] := round(FHeight * 0.28839 + Height * Boxplot);
      getHeight[9] := round(FHeight * 0.27839 + Height * Boxplot);

      // Name des Boxplots
      PaintBox.Canvas.TextOut(xWert-30, getHeight[3]-20, namen[index] + ':');

      // Einteilung/Markierung
        // Minimum
      PaintBox.Canvas.TextOut(xWert-3, getHeight[0], FloatToStr(zahlen[index][0]));
      drawLine(PaintBox, clRed, xWert, getHeight[1], xWert, getHeight[2]);

        // Maximum
      PaintBox.Canvas.TextOut(FWidth - 80, getHeight[0], FloatToStr(zahlen[index][Length(zahlen[index]) - 1]));
      drawLine(PaintBox, clRed, FWidth-80, getHeight[1], FWidth-80, getHeight[2]);

        // unteres Quartil
      PaintBox.Canvas.TextOut(round(xWert - 3 + (quartils[0] - zahlen[index][0]) * eineLaengenEinheit), getHeight[3], FloatToStr(quartils[0]));
      drawLine(PaintBox, clRed, round(xWert + (quartils[0] - zahlen[index][0])*eineLaengenEinheit), getHeight[4], round(xWert +
        (quartils[0] - zahlen[index][0])*eineLaengenEinheit), getHeight[5]);

        // median
      PaintBox.Canvas.TextOut(round(xWert - 3 + (median - zahlen[index][0]) * eineLaengenEinheit), getHeight[3], FloatToStr(median));
      drawLine(PaintBox, clRed, round(xWert + (median - zahlen[index][0])*eineLaengenEinheit), getHeight[4], round(xWert +
        (median - zahlen[index][0])*eineLaengenEinheit), getHeight[5]);

        // oberes Quartil
      PaintBox.Canvas.TextOut(round(xWert - 3 + (quartils[1] - zahlen[index][0]) * eineLaengenEinheit), getHeight[3], FloatToStr(quartils[1]));
      drawLine(PaintBox, clRed, round(xWert + (quartils[1] - zahlen[index][0]) * eineLaengenEinheit), getHeight[4], round(xWert +
        (quartils[1] - zahlen[index][0]) * eineLaengenEinheit), getHeight[5]);

        //Boxplot an sich
      drawLine(PaintBox, clBlack, xWert, getHeight[6], round(xWert + (quartils[0] - zahlen[index][0]) * eineLaengenEinheit), getHeight[6]);
      drawLine(PaintBox, clBlack, round(xWert + (quartils[0] - zahlen[index][0]) * eineLaengenEinheit), getHeight[4], round(xWert +
        (quartils[1] - zahlen[index][0]) * eineLaengenEinheit), getHeight[4]);
      drawLine(PaintBox, clBlack, round(xWert + (quartils[0] - zahlen[index][0]) * eineLaengenEinheit), getHeight[5], round(xWert +
        (quartils[1] - zahlen[index][0]) * eineLaengenEinheit), getHeight[5]);
      drawLine(PaintBox, clBlack, round(xWert + (quartils[1] - zahlen[index][0]) * eineLaengenEinheit), getHeight[6], FWidth - 80, getHeight[6]);

      //Skala
      for i := 0 to round(zahlen[index][Length(zahlen[index])-1]-zahlen[index][0]) do
        drawLine(PaintBox, clBlack, round(xWert + i * eineLaengenEinheit), getHeight[7], round(xWert + i * eineLaengenEinheit), getHeight[8]);
      drawLine(PaintBox, clBlack, xWert, getHeight[9], FWidth-80, getHeight[9]);
      end;
  end;
Findet ihr einen Fehler? Langsam verzweifle ich daran und kann mir nicht erklären woran es liegen kann :/ :(

hoika 24. Apr 2019 11:57

AW: Seltsames Verhalten einer Funktion
 
Hallo,
OK, für den schlechten Stil hast Du dich schon entschuldigt ;)

Aber:
for i := 0 to round(zahlen[index][Length(zahlen[index])-1]-zahlen[index][0]) do
und
round(xWert + i * eineLaengenEinheit), getHeight[8

Wer soll das verstehen?
Bitte benutze eine lokale Variablen und F5/F7/F8 und Strg+F5.

Ich kenne dieses Boxplots erst mal gar nicht.
Und einen Datensatz habe ich auch nicht gefunden.
Woran erkennt man, dass die Boxplots einen gleichen/unterschiedlichen Datensatz haben?

Du hattest ja geschrieben, dass es in C++ bereits funktionierte.
Gehe doch den C++ und den Delphi-Code schrittweise durch und vergleiche die Variableninhalte.

peterbelow 24. Apr 2019 12:01

AW: Seltsames Verhalten einer Funktion
 
Du rundest Gleitkommawerte auf Ganzzahlen, da kann es schon mal passieren, dass zwei Werte, die in der Dezimaldarstelllung gleich aussehen und als Nachkommateil .5 haben in der Binärdarstellung leicht unterschiedlich sind, so das einer nach oben und einer nach unten gerundet wird. Vielleicht ist das dein Problem...

freimatz 24. Apr 2019 12:14

AW: Seltsames Verhalten einer Funktion
 
Zitat:

Zitat von Pytroxis (Beitrag 1430858)
Findet ihr einen Fehler? Langsam verzweifle ich daran und kann mir nicht erklären woran es liegen kann :/ :(

Ich kann es erklären, warum du den Fehlr nicht finden kannst SCNR.

Deine Methode ist viel zu lang und komplex. Mache mehrere kleinere daraus, z.B. trenne die Berechnung und das Malen.
Und dann wie hoika schon schrieb debugge.

Jasocul 24. Apr 2019 12:32

AW: Seltsames Verhalten einer Funktion
 
Ohne den Source im Einzelnen angesehen zu haben, habe ich folgenden Verdacht:
Es gibt globale Variablen. Die Prozeduren gehören zu keinem Objekt und es wird in den Prozeduren auf die globalen Variablen zugegriffen. Bei jedem Repaint besteht die Gefahr, dass Werte aus den globalen Variablen verwendet werden, die zum anderen "Datensatz" gehören. Die Folge ist, dass mit falschen Werten gezeichnet wird.

Pytroxis 24. Apr 2019 13:05

AW: Seltsames Verhalten einer Funktion
 
Zitat:

Zitat von hoika (Beitrag 1430861)
Wer soll das verstehen?
Bitte benutze eine lokale Variablen und F5/F7/F8 und Strg+F5.

Das Problem was ich hierbei habe ist, dass die Variablen in einer anderen Procedure verwendet werden müssen (-> Sortieren des Datensatzes, errechnen des medians, der Quartils etc.). Danach werden sie erst zum zeichnen verwendet (in einer anderen Funktion). Demnach wüsste ich nicht wie ich auf lokale Variablen setzen soll außer vielleicht der lokale Variable den Wert der globalen zuzuweisen (-> andere Möglichkeit sehe ich gerade nicht, korrigiere mich bitte falls ich falsch liege).

Zitat:

Zitat von hoika (Beitrag 1430861)
Ich kenne dieses Boxplots erst mal gar nicht.
Und einen Datensatz habe ich auch nicht gefunden.
Woran erkennt man, dass die Boxplots einen gleichen/unterschiedlichen Datensatz haben?

Ein Boxplots ist das was du im Anhang gesehen hast (-> grafische Darstellung einer Verteilung).
Die Datensätze sind in
Delphi-Quellcode:
zahlen
gespeichert und sie werden durch den Nutzer eingeben oben in meinem Fall waren die Datensätze:
Delphi-Quellcode:
zahlen[0] := [0,1,2,3,4,5]
zahlen[1] := [0,1,2,3,4,6]
Der unterschied war hierbei die 5 bzw. 6 sprich das Maximum.
Im oberen Bild sieht man, dass beide Boxplots richtig dargestellt werden sofern die Datensätze gleich sind aber bei unterschiedlichen Datensätzen der obere Boxplot "verkrüppelt" ist.

Zitat:

Zitat von hoika (Beitrag 1430861)
Du hattest ja geschrieben, dass es in C++ bereits funktionierte.
Gehe doch den C++ und den Delphi-Code schrittweise durch und vergleiche die Variableninhalte.

Witzige Geschichte, dass kann ich nicht machen. Das ursprüngliche Programm war fertig, korrekt, als ich dann mit umschreiben auf Delphi soweit fertig war, wollte mein Lehrer, dass ich noch das vergleichen hinzufüge und dabei gibt es jetzt halt die Probleme.

Zitat:

Zitat von peterbelow (Beitrag 1430862)
Du rundest Gleitkommawerte auf Ganzzahlen, da kann es schon mal passieren, dass zwei Werte, die in der Dezimaldarstelllung gleich aussehen und als Nachkommateil .5 haben in der Binärdarstellung leicht unterschiedlich sind, so das einer nach oben und einer nach unten gerundet wird. Vielleicht ist das dein Problem...

Probeweise habe ich mal alle
Delphi-Quellcode:
round
durch
Delphi-Quellcode:
trunc
ersetz, da somit dieser Fehler ja nicht mehr auftreten dürfte.
Allerdings tritt er immer noch auf und es hat sich nichts verändert. Aber prinzipiell ist die Idee mit trunc statt round gar nicht so schlecht.


Zitat:

Zitat von freimatz (Beitrag 1430864)
Deine Methode ist viel zu lang und komplex. Mache mehrere kleinere daraus, z.B. trenne die Berechnung und das Malen.
Und dann wie hoika schon schrieb debugge.

Aber wie soll ich es denn weiter trennen? Die einzige Möglichkeit die ich sehe wären Arrays (-> Mit den Rechnungen etc.) und diesen dann an eine Funktion zum zeichnen weiterzugeben oder hast du eine bessere Idee? :D


Zitat:

Zitat von Jasocul (Beitrag 1430866)
Ohne den Source im Einzelnen angesehen zu haben, habe ich folgenden Verdacht:
Es gibt globale Variablen. Die Prozeduren gehören zu keinem Objekt und es wird in den Prozeduren auf die globalen Variablen zugegriffen. Bei jedem Repaint besteht die Gefahr, dass Werte aus den globalen Variablen verwendet werden, die zum anderen "Datensatz" gehören. Die Folge ist, dass mit falschen Werten gezeichnet wird.

Die Globalen Variablen werden eigentlich nur einmal verändert und zwar beim sortieren des Datensatzes.
In der Zeichnen Funktion werden ausschließlich lokale Variablen verwendet bzw. überschrieben, es werden nur aus den globalen Variablen gelesen, demnach dürften die globalen Variablen nicht verändert worden sein.


Ich habe die Datensätze auch mehrfach kontrolliert und getestet ob diese verändert werden o.ä. und das wurden sie nicht, daher wundert mich das ganze ja so sehr, dass die Darstellung einmal mit gleichen Datensätzen geht und das andere mal mit unterschiedlichen nicht mehr.
Werde jetzt mal debuggen und mich später nochmal melden :D

Pytroxis 24. Apr 2019 13:10

AW: Seltsames Verhalten einer Funktion
 
Ich habe jetzt noch nicht gedebuggt aber mir ist folgende aufgefallen:
Bisher waren die Datensätze immer
Delphi-Quellcode:
zahlen[0] := [1,2,3,4,5]
zahlen[1] := [1,2,3,4,6]
Dabei war dann der erste Boxplot verkrüppelt.
Nun habe ich die Datensätze einfach mal getauscht:
Delphi-Quellcode:
zahlen[0] := [1,2,3,4,6]
zahlen[1] := [1,2,3,4,5]
Und so werden beide ganz normal angezeigt.

Das wundert mich jetzt noch viel mehr

Edit:
Zitat:

Zitat von hoika (Beitrag 1430861)
Bitte benutze eine lokale Variablen und F5/F7/F8 und Strg+F5.

Das debuggen hat wirklich geholfen!
Habe meinen Fehler gefunden und jetzt fühle ich mich ziemlich dumm -_-
Habe vergessen die Variablen für Quartils und Median auch auf mehrere Boxplots auszulegen. Werde das jetzt mal ändern aber daran liegt es vermutlich.

Edit2:
Es lag tatsächlich an den Variablen, jetzt fühle ich mich wirklich dumm -_-

hoika 24. Apr 2019 14:04

AW: Seltsames Verhalten einer Funktion
 
Hallo,
geht doch.

die Quartils und Median sahen für mich eh schon etwas komisch aus,
die hatte ich auch im Verdacht ... ;)

Der Debugger ist Dein bester Freund.

Sherlock 24. Apr 2019 14:31

AW: Seltsames Verhalten einer Funktion
 
Zitat:

Zitat von Pytroxis (Beitrag 1430871)
Edit2:
Es lag tatsächlich an den Variablen, jetzt fühle ich mich wirklich dumm -_-

Nicht dumm! Klüger als vorher ;-)

Sherlock

Pytroxis 24. Apr 2019 15:27

AW: Seltsames Verhalten einer Funktion
 
Zitat:

Zitat von hoika (Beitrag 1430873)
Hallo,
geht doch.

die Quartils und Median sahen für mich eh schon etwas komisch aus,
die hatte ich auch im Verdacht ... ;)

Der Debugger ist Dein bester Freund.

Merk ich mir für die Zukunft :D


Zitat:

Zitat von Sherlock (Beitrag 1430876)
Nicht dumm! Klüger als vorher ;-)

Sherlock

JaJa :P

Luckie 24. Apr 2019 15:39

AW: Seltsames Verhalten einer Funktion
 
Super. So was freut einem, wie das hier gelaufen ist. Großes Lob an den Threadersteller und an die Helfer. :thumb:

Zusatzaufgabe: Jetzt noch etwas Refactoring und das ganze in eine Klasse packen. Dann kannst du beliebig viele Boxplots machen, weil jeder Boxplot ein unabhängiges Objekt mit der Klasse als Blaupause ist. Und wenn du das hier einmal kapiert und geschafft hast, fällt es beim nä htsen mal leichter; egal in welcher Programmiersprache.

Pytroxis 24. Apr 2019 16:00

AW: Seltsames Verhalten einer Funktion
 
Zitat:

Zitat von Luckie (Beitrag 1430881)
Super. So was freut einem, wie das hier gelaufen ist. Großes Lob an den Threadersteller und an die Helfer. :thumb:

Zusatzaufgabe: Jetzt noch etwas Refactoring und das ganze in eine Klasse packen. Dann kannst du beliebig viele Boxplots machen, weil jeder Boxplot ein unabhängiges Objekt mit der Klasse als Blaupause ist. Und wenn du das hier einmal kapiert und geschafft hast, fällt es beim nächstes mal leichter; egal in welcher Programmiersprache.

Habe das schon alles in eine extra Unit ausgelagert aber das mit der Klasse ist wirklich ne super Idee! Werde mich dann die nächsten Tage mal daran versuchen es umzuschreiben.
Theoretisch ist es ja nicht so schwierig, hoffe ich mal :D

Hatte bis jetzt immer eine schleife genutzt, welche die Funktion
Delphi-Quellcode:
zeichnen
aufruft (bei mehreren Boxplots).
Meinst du ich kann das so lassen oder sollte ich das, wenn ich es zu einer Klasse umschreibe, anders lösen? :)

Edit:
Oder wäre folgende Option besser -> Funktion in der Klasse die zeichnen aufruft (mit Schleife etc.). Und dann in Form2 (wo gezeichnet wird), lediglich diese Funktion statt zeichnen aufzurufen?

hoika 24. Apr 2019 16:24

AW: Seltsames Verhalten einer Funktion
 
Hallo,
jeder Boxplot hat immer die gleichen Daten(-strukturen) und Methoden.

Delphi-Quellcode:
type
  TBoxplot = class
    private
      // das haben wir später
    public
      // Variablen
      i: Integer;

      // Methoden
      procedure Zeichen;
  end;

Luckie 24. Apr 2019 16:31

AW: Seltsames Verhalten einer Funktion
 
Und die Methode Zeichnen kennt den Canvas auf dem gezeichnet werden soll. Entweder per Parameter oder Property. Dann kannst du deine Boxplots auf alles zeichnen, was ein Canvas hat: Form, Paintbox, Image, Scrollbox, ...ohne am eigentlichen Code was ändern zu müssen.

Pytroxis 24. Apr 2019 21:55

AW: Seltsames Verhalten einer Funktion
 
Witzige Geschichte die mir gerade beim umschreiben aufgefallen ist:
Ich nutze 2 Forms, auf der ersten trägt der Nutzer den Datensatz/die Datensätze ein und auf der 2. Form ist die PaintBox auf welcher gezeichnet wird.
Wenn ich das alles nun umschreibe zu einer Klasse müsste ich ja in Form 1 eine Objekt erstellen/erschaffen. Ist das aber nicht sinnlos, denn auf Form 2 musst ja ein Objekt erstellt werden um es zu zeichnen.
Habe ich gerade eine Denkfehler? Oder könnte mir jemand sagen wie ich es am geschicktesten machen sollte? :?:

scrat1979 24. Apr 2019 23:25

AW: Seltsames Verhalten einer Funktion
 
Zitat:

Zitat von Pytroxis (Beitrag 1430898)
Witzige Geschichte die mir gerade beim umschreiben aufgefallen ist:
Ich nutze 2 Forms, auf der ersten trägt der Nutzer den Datensatz/die Datensätze ein und auf der 2. Form ist die PaintBox auf welcher gezeichnet wird.
Wenn ich das alles nun umschreibe zu einer Klasse müsste ich ja in Form 1 eine Objekt erstellen/erschaffen. Ist das aber nicht sinnlos, denn auf Form 2 musst ja ein Objekt erstellt werden um es zu zeichnen.
Habe ich gerade eine Denkfehler? Oder könnte mir jemand sagen wie ich es am geschicktesten machen sollte? :?:

Ich glaube du hast einen Denkfehler. Du kannst im erstellten Objekt auf Form1 das Canvas der Paintbox auf Form2 zuweisen. Vorausgesetzt die Variable (hier: Paintbox) befindet sich im Public-Abschnitt, damit du darauf über Form1 zugreifen kannst...

//EDIT: Du brauchst damit auf Form2 also keine Instanz erstellen

bcvs 25. Apr 2019 07:05

AW: Seltsames Verhalten einer Funktion
 
ich würde sowieso die Klasse TBoxplot (oder wie auch immer die heißt) in eine eigen Unit auslagern, die dann in Form1 und Form2 eingebunden wird.
Irgendwo in Form1 wird dann eine Instanz dieser Klasse erzeugt und diese an Form2 übergeben.

Pytroxis 25. Apr 2019 14:33

AW: Seltsames Verhalten einer Funktion
 
Zitat:

Zitat von scrat1979 (Beitrag 1430901)
Du kannst im erstellten Objekt auf Form1 das Canvas der Paintbox auf Form2 zuweisen. Vorausgesetzt die Variable (hier: Paintbox) befindet sich im Public-Abschnitt, damit du darauf über Form1 zugreifen kannst...

Ich habe es jetzt mal in eine Klasse umgeschrieben, es sieht nun wie folgt aus:
Delphi-Quellcode:
type
  TBoxplot = class
    private
      FZahlen : array of array of Double;
      FNamen : TStrings;
      FQuartils : array of array[0..1] of Double;
      FMedian : array of Double;
      FBereiche: array of array[0..3] of array of Double;
      FPaintBox : TPaintBox;
      FSize : array[0..1] of Integer; // size[0] -> Höhe; size[1] -> Breite
      procedure sortiereZahlen(index: integer);
      procedure drawLine(color: TColor; minX, minY, maxX, maxY:integer);
      procedure zeichnen(Boxplot : real);
    public
      procedure einlesenZahlen(datensatz : array of TStringList; bNamen: TStrings);
      procedure boxplotErstellen(PaintBox : TPaintBox); // Ermittelt die Anzhal der Boxplots und ruft dann n-mal die zeichen Funktion auf.
    published
      constructor Create(size : array of Integer); // Den Destruktor werde ich noch hinzufügen
  end;

function isNumber(eingabe:string):Boolean;
function checkEingabe (eingabe : String) : Boolean;
procedure setButton(button:array of TButton; state : Boolean);
(Die unteren 3 Funktionen habe ich bewusst nicht in die Klasse genommen).
Ist die Deklaration soweit gut oder sollte ich etwas umändern? :)


Zitat:

Zitat von bcvs (Beitrag 1430911)
ich würde sowieso die Klasse TBoxplot (oder wie auch immer die heißt) in eine eigen Unit auslagern, die dann in Form1 und Form2 eingebunden wird.

Hatte ich so oder so gemacht, alleine schon weil es übersichtlicher ist :D

Zitat:

Zitat von bcvs (Beitrag 1430911)
Irgendwo in Form1 wird dann eine Instanz dieser Klasse erzeugt und diese an Form2 übergeben.

Das erstellen in Form 1 ist kein Problem allerdings habe ich beim übergeben ein Problem:
Wie übergebe ich die Instanz am besten? Hatte mir überlegt auf Form2 eine variable von der Klasse zu erstellen und dann dieser in Form1 die Instanz zuzuweisen (-> Ich muss auf Form2 die ChangeSize/OnPaint nutzen, da die Größe dynamisch ist).
Allerdings muss ich die Variable auf Form2 ja "erstellen". Dann müsste ich aber doch den Konstruktor erneut aufrufen und erzeuge somit doch eine neue Instanz oder habe ich auch hier ein Denkfehler?

hoika 25. Apr 2019 15:18

AW: Seltsames Verhalten einer Funktion
 
Hallo,
ja du hast einen Denkfehler ;)

Zitat:

die Variable auf Form2 ja "erstellen"
Die Variable in Form2 ist ein Platzhalter.
Form2.BoxPlot:= Self.BoxPlot; / Self=Form1)

BoxPlot in Form2 wird weder erstellt noch freigegeben.

Pytroxis 26. Apr 2019 10:37

AW: Seltsames Verhalten einer Funktion
 
Zitat:

Zitat von hoika (Beitrag 1430954)
Hallo,
Die Variable in Form2 ist ein Platzhalter.
Form2.BoxPlot:= Self.BoxPlot; / Self=Form1)

BoxPlot in Form2 wird weder erstellt noch freigegeben.

Jep das hat wunderbar funktioniert!
Hab es jetzt so gelöst:
Form1:
-erstellen der Variable/Instanz mithilfe von Create.
-Verschiedenen Datensätze in die Instanz einlesen.

Form2:
-Boxplot erstellen lassen.

Ich gehe mal davon aus, dass man normalerweise für jeden Boxplot eine Instanz erstellen würde, allerdings habe ich insgesamt nur eine Instanz für alle Boxplots erstellt.
Hierbei lasse ich dann einfach eine Schleife x Boxplots zeichnen, je nachdem wie viele Datensätze vorhanden sind.

Aber effektiv habe ich mir doch durch den umschrieb jetzt nichts gespart :D
Hätte ich einen Array vom Typ meiner Klasse erzeugt (wo jeder Index eine Instanz ist) hätte es doch mehr gebracht oder bin ich gerade nur dumm? :D


Prinzipiell geht jetzt alles, vielen Dank dafür!
Werde die Tage jetzt nur noch meinen Code aufräumen und versuchen so kompakt wie möglich zu schreiben :D

peterbelow 26. Apr 2019 10:47

AW: Seltsames Verhalten einer Funktion
 
Zitat:

Zitat von Pytroxis (Beitrag 1431039)

Prinzipiell geht jetzt alles, vielen Dank dafür!
Werde die Tage jetzt nur noch meinen Code aufräumen und versuchen so kompakt wie möglich zu schreiben :D

Falsches Ziel, schreibe den Kode verständlich, das ist viel wichtiger als kompakt.

freimatz 26. Apr 2019 12:24

AW: Seltsames Verhalten einer Funktion
 
Finde ich auch - und vermutlich der Lehrer auch :lol:

hoika 26. Apr 2019 14:56

AW: Seltsames Verhalten einer Funktion
 
Hallo,
Zitat:

verständlich
Das ist doch aber schlecht!!!
Dann könnte später ein Kollege am Code weiterarbeiten und man wäre ersetzbar ... ;)

Pytroxis 26. Apr 2019 15:22

AW: Seltsames Verhalten einer Funktion
 
Zitat:

Zitat von peterbelow (Beitrag 1431042)
Zitat:

Zitat von Pytroxis (Beitrag 1431039)

Prinzipiell geht jetzt alles, vielen Dank dafür!
Werde die Tage jetzt nur noch meinen Code aufräumen und versuchen so kompakt wie möglich zu schreiben :D

Falsches Ziel, schreibe den Kode verständlich, das ist viel wichtiger als kompakt.

Um ehrlich zu sein ist es nicht das falsche Ziel. Ich muss ja nicht nur den Code abgeben sondern noch eine schriftliche Ausfertigung dazu wo ich alles erkläre.
Diese Ausfertigung darf maximal 12 Din A4 Seiten füllen, es hört sich zwar einfach an aber das ist es definitiv nicht (12 Seiten sind verdammt wenig).
Ich bin jetzt schon, ohne den Vergleich von Boxplots bei ca. 12 Seiten, demnach muss ich versuchen so viel wie möglich zu kürzen.
Ich erkläre sowieso alles in der Ausfertigung, zudem werden Kommentare im Code alles erklären.
Der Code soll eigentlich nur "Beiwerk" sein, die Facharbeit konzentriert sich auf das erklären des Programmes und wie ich es gelöst habe.
Außerdem meinte ich mit kompakt, dass ich Dinge weg lasse/auslagere die "unnötig" sind und umständliche Sachen einfacher schreiben will :)
Die Facharbeit ist soweit fertig, allerdings muss ich den vergleich noch einbringen und das wird schwierig.
Zur Krönung des ganzen: Ich habe meinen Lehrer gefragt ob ich ihm eine E-Mail schreiben kann um mit ihm alles zu besprechen, in dieser E-Mail war die erste Version meiner Facharbeit und ich fragte Ihn ob ich es so machen kann, diese E-Mail ist nun fast eine Woche her und bisher habe ich keine Reaktion erhalten.
Und um es noch schöner zu gestalten: Am 07.05. ist die Abgabe, d.h. ich habe nicht mehr viel Zeit die schriftliche Ausfertigung zu machen und es ist natürlich nicht schön, dass man an der "einfachsten" Aufgabe nun hängt, weil man nicht genau weiß wie man es machen soll -_-
(PS: Wir haben Ferien daher kann ich ihn nicht persönlich fragen und ich habe es nicht vor mir hin geschoben, die erste Version (in C++) war schon im Dezember fertig, allerdings hatte er bis vor kurzem die ganze Zeit über keine Zeit).



Zitat:

Zitat von hoika (Beitrag 1431068)
Das ist doch aber schlecht!!!
Dann könnte später ein Kollege am Code weiterarbeiten und man wäre ersetzbar ... ;)

Witzige Geschichte, in meinem gesamten Kurs (ca. 15-20 Schüler) gibt es genau 2 Personen die Programmieren können und ich bin eine davon :D
Das ersetzen wird daher vielleicht etwas schwerer :P

hoika 26. Apr 2019 15:31

AW: Seltsames Verhalten einer Funktion
 
Hallo,
Zitat:

(12 Seiten sind verdammt wenig).
Ist die Schriftgröße vorgegeben? ;)

Pytroxis 26. Apr 2019 21:35

AW: Seltsames Verhalten einer Funktion
 
Zitat:

Zitat von hoika (Beitrag 1431070)
Hallo,
Zitat:

(12 Seiten sind verdammt wenig).
Ist die Schriftgröße vorgegeben? ;)

Jep auch die Schriftart...

Aber nach einer erneuten E-Mail hat er geantwortet, habe jetzt mal einen Anhaltspunkt. wünscht mir Glück :D

Pytroxis 27. Apr 2019 16:33

AW: Seltsames Verhalten einer Funktion
 
Vielleicht könnt ihr mir gerade noch diese kurze Frage beantworten:
Ich habe meinen Code ja mittlerweile zu einer Klasse umgeschrieben.
Normalerweise würde man doch für jeden Boxplot eine Instanz erstellen, allerdings habe ich insgesamt nur eine Instanz für alle Boxplots erstellt.
Hierbei lasse ich dann einfach eine Schleife x Boxplots zeichnen, je nachdem wie viele Datensätze vorhanden sind.

Aber effektiv habe ich mir doch durch den umschrieb jetzt nichts gespart
Hätte ich einen Array vom Typ meiner Klasse erzeugt (wo jeder Index eine Instanz ist) hätte es doch mehr gebracht oder bin ich gerade nur dumm? :pale:

scrat1979 27. Apr 2019 20:53

AW: Seltsames Verhalten einer Funktion
 
Zitat:

Zitat von Pytroxis (Beitrag 1431136)

Aber effektiv habe ich mir doch durch den umschrieb jetzt nichts gespart
Hätte ich einen Array vom Typ meiner Klasse erzeugt (wo jeder Index eine Instanz ist) hätte es doch mehr gebracht oder bin ich gerade nur dumm? :pale:

Also ich hätte statt einem Array eine - bestenfalls generische - TObjectList genommen.. Wie der Name schon sagt ist diese genau dafür gedacht und hat auch schon sehr hilfreiche Methoden zur Verwaltung der Liste implementiert..

Pytroxis 27. Apr 2019 21:34

AW: Seltsames Verhalten einer Funktion
 
Zitat:

Zitat von scrat1979 (Beitrag 1431159)
Also ich hätte statt einem Array eine - bestenfalls generische - TObjectList genommen.. Wie der Name schon sagt ist diese genau dafür gedacht und hat auch schon sehr hilfreiche Methoden zur Verwaltung der Liste implementiert..

Okay danke, werde es mir angucken und dann überlegen ob ich für jeden Boxplot eine eigene Instanz erstelle oder einfach weiterhin eine Instanz für alles nutze, bis jetzt funktioniert alles und ich glaube andernfalls müsste ich alles umschreiben :D

Pytroxis 28. Apr 2019 14:10

AW: Seltsames Verhalten einer Funktion
 
Zitat:

Zitat von hoika (Beitrag 1430861)
Wer soll das verstehen?.

Hatte es nochmal überarbeitet und versucht übersichtlicher zu gestalten.
Meine Lösung ist nun:

Delphi-Quellcode:
procedure TBoxplot.zeichnen(Boxplot : real);
  var i, xWert, index: integer;
      eineLaengeneinheit : Double;
      getHeight : array[0..9] of integer;
      getWidth : array[0..3] of integer;
  begin
    if Length(FZahlen) > 0 then begin
      xWert := 50;
      index := trunc(Boxplot);

      eineLaengeneinheit := (FSize[1]-120) / (FZahlen[index][High(FZahlen[index])] - FZahlen[index][0]);


      getHeight[0] := round(FSize[0] * 0.31919 + FHeight * Boxplot);
      getHeight[1] := round(FSize[0] * 0.13214 + FHeight * Boxplot);
      getHeight[2] := round(FSize[0] * 0.18379 + FHeight * Boxplot);
      getHeight[3] := round(FSize[0] * 0.04839 + FHeight * Boxplot);
      getHeight[4] := round(FSize[0] * 0.09839 + FHeight * Boxplot);
      getHeight[5] := round(FSize[0] * 0.21839 + FHeight * Boxplot);
      getHeight[6] := round(FSize[0] * 0.15839 + FHeight * Boxplot);
      getHeight[7] := round(FSize[0] * 0.26839 + FHeight * Boxplot);
      getHeight[8] := round(FSize[0] * 0.28839 + FHeight * Boxplot);
      getHeight[9] := round(FSize[0] * 0.27742 + FHeight * Boxplot);

      getWidth[0] := round(xWert + (FQuartils[index][0] - FZahlen[index][0]) * eineLaengenEinheit);
      getWidth[1] := round(xWert + (FMedian[index] - FZahlen[index][0]) * eineLaengenEinheit);
      getWidth[2] := round(xWert-1 + (FQuartils[index][1] - FZahlen[index][0]) * eineLaengenEinheit);



      // Name des Boxplots
      FPaintBox.Canvas.TextOut(xWert-20, getHeight[3]-20, FNamen[index] + ':');

      // Einteilung/Markierung
        // Minimum
      FPaintBox.Canvas.TextOut(xWert-5, getHeight[0], FloatToStr(FZahlen[index][0]));
      drawLine(clRed, xWert, getHeight[1], xWert, getHeight[2]);

        // Maximum
      FPaintBox.Canvas.TextOut(FWidth-5, getHeight[0], FloatToStr(FZahlen[index][High(FZahlen[index])]));
      drawLine(clRed, FWidth, getHeight[1], FWidth, getHeight[2]);

        // unteres Quartil
      FPaintBox.Canvas.TextOut(getWidth[0]-5, getHeight[3], FloatToStr(FQuartils[index][0]));
      drawLine(clRed, getWidth[0], getHeight[4], getWidth[0], getHeight[5]);

        // FMedian[index]
      FPaintBox.Canvas.TextOut(getWidth[1]-5, getHeight[3], FloatToStr(FMedian[index]));
      drawLine(clRed, getWidth[1], getHeight[4], getWidth[1], getHeight[5]);

        // oberes Quartil
      FPaintBox.Canvas.TextOut(getWidth[2]-5, getHeight[3], FloatToStr(FQuartils[index][1]));
      drawLine(clRed, getWidth[2], getHeight[4], getWidth[2], getHeight[5]);

        //Boxplot an sich
      drawLine(clBlack, xWert, getHeight[6], getWidth[0], getHeight[6]);
      drawLine(clBlack, getWidth[0], getHeight[4], getWidth[2], getHeight[4]);
      drawLine(clBlack, getWidth[0], getHeight[5], getWidth[2], getHeight[5]);
      drawLine(clBlack, getWidth[2], getHeight[6], FWidth, getHeight[6]);

      //Skala
      for i := 0 to round(FZahlen[index][High(FZahlen[index])]-FZahlen[index][0]) do begin
        getWidth[3] := round(xWert + i * eineLaengenEinheit);
        drawLine(clBlack, getWidth[3], getHeight[7], getWidth[3], getHeight[8]);
      end;
      drawLine(clBlack, xWert, getHeight[9], FWidth, getHeight[9]);
    end;
  end;
Ist das so schon mal verständlicher? :D
Und habt Ihr noch Tipps es übersichtlicher/verständlicher zu schreiben? :)

Klaus01 28. Apr 2019 14:23

AW: Seltsames Verhalten einer Funktion
 
..wo kommen denn diese "magischen" Werte her?

Delphi-Quellcode:
      getHeight[0] := round(FSize[0] * 0.31919 + FHeight * Boxplot);
      getHeight[1] := round(FSize[0] * 0.13214 + FHeight * Boxplot);
      getHeight[2] := round(FSize[0] * 0.18379 + FHeight * Boxplot);
      getHeight[3] := round(FSize[0] * 0.04839 + FHeight * Boxplot);
      getHeight[4] := round(FSize[0] * 0.09839 + FHeight * Boxplot);
      getHeight[5] := round(FSize[0] * 0.21839 + FHeight * Boxplot);
      getHeight[6] := round(FSize[0] * 0.15839 + FHeight * Boxplot);
      getHeight[7] := round(FSize[0] * 0.26839 + FHeight * Boxplot);
      getHeight[8] := round(FSize[0] * 0.28839 + FHeight * Boxplot);
      getHeight[9] := round(FSize[0] * 0.27742 + FHeight * Boxplot);
Um es lesbarer zu gestalten, vielleicht die Werte durch Konstante ersetzen.
Oder die Werte in ein Array stecken, mit den gleichen Indizes wie getHigh.
Dann könntest Du das alles in eine Schleife von 0 bis 9 abarbeiten.

Grüße
Klaus

Pytroxis 28. Apr 2019 15:45

AW: Seltsames Verhalten einer Funktion
 
Zitat:

Zitat von Klaus01 (Beitrag 1431222)
..wo kommen denn diese "magischen" Werte her?

Delphi-Quellcode:
      getHeight[0] := round(FSize[0] * 0.31919 + FHeight * Boxplot);
      getHeight[1] := round(FSize[0] * 0.13214 + FHeight * Boxplot);
      getHeight[2] := round(FSize[0] * 0.18379 + FHeight * Boxplot);
      getHeight[3] := round(FSize[0] * 0.04839 + FHeight * Boxplot);
      getHeight[4] := round(FSize[0] * 0.09839 + FHeight * Boxplot);
      getHeight[5] := round(FSize[0] * 0.21839 + FHeight * Boxplot);
      getHeight[6] := round(FSize[0] * 0.15839 + FHeight * Boxplot);
      getHeight[7] := round(FSize[0] * 0.26839 + FHeight * Boxplot);
      getHeight[8] := round(FSize[0] * 0.28839 + FHeight * Boxplot);
      getHeight[9] := round(FSize[0] * 0.27742 + FHeight * Boxplot);

Wie man der Procedure entnehmen kann ist sie ein Teil der Klasse.
FSize und FHeight sind Variablen der Klasse welche beim erstellen gesetzt werden. Ebenfalls werden diese bei dem ändern der Fenstergröße gesetzt.
-> in FSize ist die Fenstergröße und in FHeight die Größe eines Boxplots (relativ zur Fenstergröße).
-> Boxplot : Boxplot welcher gerade gezeichnet wird, muss demnach auch variable sein.


Zitat:

Zitat von Klaus01 (Beitrag 1431222)
Um es lesbarer zu gestalten, vielleicht die Werte durch Konstante ersetzen.
Oder die Werte in ein Array stecken, mit den gleichen Indizes wie getHigh.
Dann könntest Du das alles in eine Schleife von 0 bis 9 abarbeiten.

Grüße
Klaus

Wie oben beschrieben, kann ich die Werte nicht durch konstanten ersetzen.
Die Werte sind abhängig der Fenstergröße und ändern sich demnach, wenn man die Größe des Fensters verändert.

Klaus01 28. Apr 2019 15:59

AW: Seltsames Verhalten einer Funktion
 
.. ich meinte diese Werte "0.31919, ..."

Grüße
Klaus

Pytroxis 28. Apr 2019 19:34

AW: Seltsames Verhalten einer Funktion
 
Zitat:

Zitat von Klaus01 (Beitrag 1431230)
.. ich meinte diese Werte "0.31919, ..."

Grüße
Klaus

Als ich eben darüber nachgedacht habe ist es mir auch klar geworden.
Bin gerade einfach zu übermüdet :(
Aber vielen Dank für den Tipp, werde sie auslagern in die Create-Function und dort als Konstanten setzen und später über eine Schleife die Werte machen C:


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