Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Datenbanken (https://www.delphipraxis.net/15-datenbanken/)
-   -   Delphi komplexe Berechnungen von abhängigen Datenbankfeldern (https://www.delphipraxis.net/63021-komplexe-berechnungen-von-abhaengigen-datenbankfeldern.html)

Emilio 12. Feb 2006 21:08

Datenbank: DBISAM • Version: 4.21 • Zugriff über: Native

komplexe Berechnungen von abhängigen Datenbankfeldern
 
Hallo Leute,

nachdem ich nun in mehreren Büchern und nach einigen DP-Sitzungen noch weniger schlau bzw. ausreichend verwirrt bin, möchte ich das Problem erstmal grob schildern:

Habe eine Query aus mittlerweile 12 tables und stelle die Werte mit DBLabels dar. Diese Werte werden für weitere Berechnungen, welche zunächst nicht gespeichert werden müssen, benötigt. Und zwar in der Form, dass der User z.B. einen neuen EK-Preis in ein Editfeld einträgt (hab bisher keine schlauere Idee), mittels einer Combobox einen Handlingsaufschlag wählt und damit den EK2 erhält. Dem User soll für den VK ein Vorschlag gemacht werden, den er aber ändern kann. Wenn er dies tut, so soll der Brutto-Preis errechnet werden (in Abhähngigkeit des MwSt-Satzes) und die Felder [Marge€], [Marge%], [Provision] sollen ausgefüllt werden. Jedoch soll der User auch die Möglichleit haben, in letztere Felder Werte seiner Wahl einzutragen und die vorhergehenden sollten errechnet werden. Zu allem Überfluss sollte eine Reihe von Feldern die Veränderungen eines jedes Feldes Alt zu Neu in % ausweisen.
Wichtig zu wissen ist, dass nur neue Datensätz erzeugt werden sollen, also keine Änderungen oder Löschungen.

Ich bekomme das bislang nur hin, in dem ich unter viel Formatierungsaufwand mit den Feldinhalten rechne - scheitere aber an dem Punkt, die neuen Werte so aufzubereiten, dass sie in die Tabelle die es betrifft eingefügt werden können.

Ein DP-Mitglied gab mir die Empfehlung den Rechenkram von der Visualisierung zu trennen - ist bestimmt gut - aber wie? Die neuen Werte müssen doch erst vom User teilweise eingegeben werden und sollen noch vor dem speichern mit allen Folgewerten vorliegen ???

memTable, ParambyName, subquery, Rembrandt?


Mir drehts sich auch schon im Kreis

Kann mir jemand sagen, auf welchen Weg ich mich begeben soll?

Viele Grüße
Emilio

[edit=MrSpock]Titel geändert. Mfg, MrSpock[/edit]

marabu 13. Feb 2006 10:27

Re: Katze beißt sich in den eigenen Schwanz - komplexe Frage
 
Hallo Emilio,

das römische Imperium ist untergegangen und so führen heute leider nicht mehr alle Wege nach Rom.

Aus dem thread, in dem ich dir den Rat gab alle Rechenvorschriften aus der Benutzerschnittstelle heraus zu halten, kenne ich zumindest eine Rechenvorschrift. Du wirst mehrere benötigen, da du ja von verschiedenen Punkten ausgehen willst.

Prinzipiell musst du fixe (Konstanten) und veränderliche (Variablen) Werte in deinen Berechnungen unterscheiden. Du hattest die Buchstaben a bis m vergeben - ich halte mich hier daran, auch wenn ich eine andere Benennung besser fände. Ich notiere Konstanten mit Großbuchstaben, Variablen mit Kleinbuchstaben.

Deine Rechenvorschrift hatte folgenden Aufbau:

Delphi-Quellcode:
procedure TForm1.cxLookupComboBox1PropertiesCloseUp(Sender: TObject);
var
  a, c, d , e, f , g, h, i, j, k, l, m, n : Double;
  b : Integer;
begin
  a := StrToFloat(cxTextEdit1.Text);
  b := StrToInt(cxLookupComboBox1.Text);
  c := a+(a*b/100);
  d := (a/60*100);
  e := (d-a);
  f := (d-a)*100/d;
  g := (d-c)*StrToFloat(cxDBLabel13.Caption)/100;
  h := (d*116/100);
  i := StrToFloat(cxDBLabel5.Caption);
  j := ((c/i)-1)*100;
  k := StrToFloat(cxDBLabel9.Caption);
  l := ((d/k)-1)*100;
  m := StrToFloat(cxLabel28.Caption);
  n := ((h/m)-1)*100;

  cxLabel14.Caption := Format('EUR ' + '%8.2f', [a+(a*b/100)]);
  cxTextEdit5.Text := Format('EUR ' + '%8.2f', [d]);
  cxTextEdit2.Text := Format('EUR ' + '%8.2f', [e]);
  cxTextEdit3.Text := Format('%5.2f', [f]) + '%';
  cxTextEdit6.Text := Format('EUR ' + '%8.2f', [g]);
  cxTextEdit4.Text := Format('EUR ' + '%8.2f', [h]);
  cxLabel18.Caption := Format('%4.2f', [j]) + '%';
  cxLabel19.Caption := Format('%4.2f', [l]) + '%';
  cxLabel24.Caption := Format('%4.2f', [n]) + '%';
end;
Ich gehe davon aus, dass alle cxTextEdit Eingabefelder darstellen. Aus deinem Code leite ich folgende funktionale Abhängigkeiten ab:

Code:
A=cxTextEdit1
b=cxLookupComboBox1
O=cxDBLabel13
I=cxDBLabel5
K=cxDBLabel9
M=cxLabel28

f_c(A,b)
f_d(A)
f_e(A,d)
f_f(A,d)
f_g(c,d,O)
f_h(d)
f_j(c,I)
f_l(d,K)
f_n(h,M)
Die Funktionen (f_c..f_h,f_j,f_l,f_n) realisierst du im implementation Abschnitt der Unit, in der du deine Rechenvorschriften speicherst. Im interface Abschnitt dieser Unit befinden sich die Funktionen für die Rechenvorschriften. Jede Rechenvorschrift hat eine bestimmte Signatur - das sind die Eingabe- und Ausgabeparameter.

Delphi-Quellcode:
unit CalcMdl;

interface

  procedure CalcRule01(A,I,K,M,O: Extended; b: Integer; var c,d,e,f,g,h,j,l,n: Extended);

implementation

  function f_c(A: Extended; b: Integer): Extended; forward;


function f_c(A: Extended; b: Integer): Extended;
begin
  Result := a + (a * b / 100);
end;


procedure CalcRule01(A,I,K,M,O: Extended; b: Integer; var c,d,e,f,g,h,j,l,n: Extended);
begin
  c := f_c(A, b);
  d := f_d(A);
  e := f_e(A, d);
  f := f_f(A, d);
  g := f_g(c, d, O);
  h := f_h(d);
  j := f_j(c, I);
  l := f_l(d, K);
  n := f_n(h, M);
end;

end.
Das Durchrechnen der Werte als Reaktion auf die Änderung in der ComboBox geschieht dann so:

Delphi-Quellcode:
procedure TForm1.cxLookupComboBox1PropertiesCloseUp(Sender: TObject);
var
  A, c, d , e, f , g, h, I, j, K, l, M, n, O: Extended;
  b : Integer;
begin
  A := StrToFloat(cxTextEdit1.Text);
  I := StrToFloat(cxDBLabel5.Caption);
  K := StrToFloat(cxDBLabel9.Caption);
  M := StrToFloat(cxLabel28.Caption);
  O := StrToFloat(cxDBLabel13.Caption);
  b := StrToInt(cxLookupComboBox1.Text);

  CalcRule01(A, I, K, M, O, b, c, d, e, f, g, h, j, l, n);

  cxLabel14.Caption := Format('EUR ' + '%8.2f', [c]);
  cxTextEdit5.Text := Format('EUR ' + '%8.2f', [d]);
  cxTextEdit2.Text := Format('EUR ' + '%8.2f', [e]);
  cxTextEdit3.Text := Format('%5.2f', [f]) + '%';
  cxTextEdit6.Text := Format('EUR ' + '%8.2f', [g]);
  cxTextEdit4.Text := Format('EUR ' + '%8.2f', [h]);
  cxLabel18.Caption := Format('%4.2f', [j]) + '%';
  cxLabel19.Caption := Format('%4.2f', [l]) + '%';
  cxLabel24.Caption := Format('%4.2f', [n]) + '%';
end;
Das verstehe ich unter Trennung. Beachte auch, dass ich Double durch Extended ersetzt habe - wegen der höheren Rechengenauigkeit. Wenn du alle Berechnungsvorschriften entworfen hast, dann wirst du eventuell feststellen, dass manche Elementarfunktion (f_c, f_d, ...) nur einmal verwendet wird. Es steht dir dann frei solche "internen" Funktionen zu integrieren. Und noch einmal mein Rat über eine Namenskonvention für dein Programm nachzudenken - du wirst es nicht bereuen.

Grüße vom marabu

sakura 13. Feb 2006 11:03

Re: Katze beißt sich in den eigenen Schwanz - komplexe Frage
 
Hi,

ändere bitte noch den Titel so, dass dieser auch aussagekräftig ist.

Danke,
...:cat:...

Emilio 13. Feb 2006 21:30

Flut v. Rechenvorgängen v. Visualisierung trennen
 
Hi Marabu,

vielen vielen Dank!
Bin dabei Deine Ausführungen umzusetzen (wobei für Dich der Code jetzt verständlicher ist, ist er für mich sehr viel aufwändiger zu lesen - ich tue mich mit der Abstraktion leichter, da ich dann die Rechenformeln leichter formulieren und lesen kann).

Eine Frage zur der Funktion, die Du beispielweise anführst: muss die Deklaration der Funktion nicht im Interface-Abschnitt erfolgen? Wenn nein, warum nicht?

So, jetzt bastel ich erstmal weiter an der "Übersetzung".

Viele Grüße

Emilio

Emilio 13. Feb 2006 21:39

Re: Katze beißt sich in den eigenen Schwanz - komplexe Frage
 
@sakura,

:gruebel: wie geht'n das mit dem sräd-Titel ändern?

marabu 13. Feb 2006 21:44

Re: Katze beißt sich in den eigenen Schwanz - komplexe Frage
 
Hi Emilio,

nur die Rechenvorschriften gehören in den interface Abschnitt, weil sie von außen erreichbar sein müssen. f_c() ist eine rein interne Funktion und gehört deswegen in den implementation Abschnitt. Da ich dort nicht ausschließen kann, dass die Basis-Funktionen sich in unterschiedlicher Reihenfolge gegenseitig rufen, deklariere ich sie zuerst mit der forward Direktive.

Gute Nacht

marabu

PS: du kannst den Titel ändern, wenn du deinen ersten Beitrag bearbeitest.

turboPASCAL 13. Feb 2006 21:44

Re: Katze beißt sich in den eigenen Schwanz - komplexe Frage
 
Zitat:

Zitat von Emilio
:gruebel: wie geht'n das mit dem sräd-Titel ändern?

Im (Deinem) ersten Beitrag auf Edit klicken und im Titeleditfeld den Titel ändern ;)

Emilio 14. Feb 2006 21:22

Re: Katze beißt sich in den eigenen Schwanz - komplexe Frage
 
Hi @all,

das mit dem Thema-Titel ändern geht nicht mehr ... vielleicht kann ja einer der Mods eingreifen?

@Marabu,


Zitat:

Zitat von marabu
Hi Emilio,

nur die Rechenvorschriften gehören in den interface Abschnitt, weil sie von außen erreichbar sein müssen. f_c() ist eine rein interne Funktion und gehört deswegen in den implementation Abschnitt. Da ich dort nicht ausschließen kann, dass die Basis-Funktionen sich in unterschiedlicher Reihenfolge gegenseitig rufen, deklariere ich sie zuerst mit der forward Direktive.

Zitat:

Zitat von marabu
Die Funktionen (f_c..f_h,f_j,f_l,f_n) realisierst du im implementation Abschnitt der Unit, in der du deine Rechenvorschriften speicherst. Im interface Abschnitt dieser Unit befinden sich die Funktionen für die Rechenvorschriften. Jede Rechenvorschrift hat eine bestimmte Signatur - das sind die Eingabe- und Ausgabeparameter.

:wiejetzt: Also schreibe ich die anderen Funktionen in ähnlicher Art und Weise in eine neue Unit. In der UnitMain entferne ich das Gerümpel und lasse i.B. die procedure mit der Combobox in derUnitMain stehen? - irgendwie stehe ich doch noch auf dem Schlauch: woher weiß dann die procedure der combobox was von den Rechenvorschriften?

Emilio

marabu 15. Feb 2006 06:06

Re: Katze beißt sich in den eigenen Schwanz - komplexe Frage
 
Guten Morgen Emilio,

ich unterscheide Berechnungsvorschriften von mathematischen Funktionen. Die Vorschriften müssen in den interface Abschnitt der Unit CalcMdl, weil sie für die ComboBox in deiner MainForm sichtbar sein müssen. Dazu bindest du die Unit CalcMdl per USES in den implementation Abschnitt deiner MainForm ein und schon kannst du aus dem event handler der ComboBox alle Vorschriften aufrufen. Die mathematischen Funktionen (z.B. Berechnung eines Prozentsatzes) werden nur von den Vorschriften benötigt und deshalb im implementation Abschnitt der Unit CalcMdl deklariert.

Du kannst alle Vorschriften und Funktionen in einer einzigen Unit (CalcMdl, dein Kalkulationsmodell) unterbringen. Dein Code wird wohl nie so umfangreich werden, als dass sich eine eigene Unit je Berechnungsvorschrift lohnen wird.

Grüße vom marabu

Emilio 15. Feb 2006 10:22

Re: komplexe Berechnungen von abhängigen Datenbankfeldern
 
Hi Marabu,

Die Calc-Unit habe ich eingebunden - das war kein Thema.

Beim Compilieren erhalte ich nun die Fehlermeldung:

"inkompatible Typen Integer und Extended",

sowie die Fehlermeldung

"nicht genügend wirkliche Parameter"

Der Cursor steht für beide Meldungen in der Zeile

(UnitMain wohlbemerkt): CalcRule01( ...);, welche ich aus Deinem script übernommen habe.

Sollte ich noch ne Kleinigkeit übersehen haben? Die Variablen a (jetzt "ekneu") und b (jetzt "zuschlag") sind als Integer deklariert, in beiden Units.

VG
Emilio

marabu 15. Feb 2006 10:43

Re: komplexe Berechnungen von abhängigen Datenbankfeldern
 
Emilio, du wirst doch die Signatur von CalcRule01() an deine geänderten Bedürfnisse angepasst haben? A war bei meinem Beispiel ja noch Extended...

marabu

Emilio 15. Feb 2006 11:04

Re: komplexe Berechnungen von abhängigen Datenbankfeldern
 
Ups, hab ich mich doch verschrieben, ich meinte

die Variablen a = zuschlag und b = ProvSatz

sind als Integer deklariert, da sie solche sind.

Ich stell mal den neuen Code rein:

Unit Main:

Delphi-Quellcode:
procedure TForm1.cxLookupComboBox1PropertiesCloseUp(Sender: TObject);

var
  ekneu, bpneu, lvpneu , margeEneu, margeprozneu , provlvpneu, bruttolvpneu, bpaender, lvpaender, bruttolvpaender, BPALT, LVPAlt, BruttoLVPAlt : Extended;
  zuschlag, ProvSatz : Integer;
begin
  ekneu := StrToFloat(cxTextEdit1.Text);  
  BPAlt := StrToFloat(cxDBLabel5.Caption);
  LVPAlt := StrToFloat(cxDBLabel9.Caption);
  BruttoLVPAlt := StrToFloat(cxLabel17.Caption);
  ProvSatz := StrToInt(cxDBLabel13.Caption);
  zuschlag := StrToInt(cxLookupComboBox1.Text);

  CalcRule01(ekneu, bpneu, lvpneu, margeEneu, margeprozneu, provlvpneu, bruttolvpneu, bpaender, lvpaender, bruttolvpaender, BPALT, LVPAlt, BruttoLVPAlt, ProvSatz, zuschlag);

  cxLabel14.Caption := Format('EUR ' + '%8.2f', [bpneu]);
  cxTextEdit5.Text := Format('EUR ' + '%8.2f', [lvpneu]);
  cxTextEdit2.Text := Format('EUR ' + '%8.2f', [margeEneu]);
  cxTextEdit3.Text := Format('%5.2f', [margeprozneu]) + '%';
  cxTextEdit6.Text := Format('EUR ' + '%8.2f', [provlvpneu]);
  cxTextEdit4.Text := Format('EUR ' + '%8.2f', [bruttolvpneu]);
  cxLabel18.Caption := Format('%4.2f', [bpaender]) + '%';
  cxLabel19.Caption := Format('%4.2f', [lvpaender]) + '%';
  cxLabel24.Caption := Format('%4.2f', [bruttolvpaender]) + '%';
end;
und die zweite unit:

Delphi-Quellcode:

unit Kalk;

interface

procedure CalcRule01(EKAlt,BPAlt,LVPAlt,BruttoLVPAlt,MargeEAlt, MargeProzAlt, ProvLVPAlt, MwSt: Extended;
   zuschlag,ProvSatz: Integer;
   var ekneu, bpneu,lvpneu,margeEneu,margeprozneu,provlvpneu,bruttolvpneu,bpaender,lvpaender,bruttolvpaender,
   ekaender, margeEaender, margeprozaender, provlvpaender: Extended);

implementation

function f_bpneu(ekneu: Extended; zuschlag: Integer): Extended; forward;
function f_lvpneu(ekneu: Extended): Extended; forward;
function f_margeEneu(ekneu: Extended; lvpneu: Extended):Extended; forward;
function f_margeprozneu(ekneu: Extended; lvpneu: Extended):Extended; forward;
function f_provlvpneu(bpneu: Extended; lvpneu: Extended; ProvSatz: Integer):Extended; forward;
function f_bruttolvpneu(lvpneu: Extended; MwSt: Extended): Extended; forward;
function f_ekaender(ekneu: Extended; EKAlt: Extended): Extended; forward;
function f_bpaender(bpneu: Extended; BPAlt: Extended): Extended; forward;
function f_lvpaender(lvpneu: Extended; LVPAlt: Extended): Extended; forward;
function f_bruttolvpaender(bruttolvpneu: Extended; BruttoLVPAlt: Extended): Extended; forward;
function f_margeEaender(margeEneu: Extended; MargeEAlt: Extended): Extended; forward;
function f_margeprozaender(margeEneu: Extended; MargeEAlt: Extended): Extended; forward;
function f_provlvpaender(provlvpneu: Extended; ProvLVPAlt: Extended): Extended; forward;

function f_bpneu(ekneu: Extended; zuschlag: Integer): Extended;
  begin
    Result := ekneu + (ekneu * zuschlag / 100);
  end;

function f_lvpneu(ekneu: Extended): Extended;
  begin
    Result := ekneu/55*100;
  end;

function f_margeEneu(ekneu: Extended; lvpneu: Extended): Extended;
  begin
    Result := lvpneu-ekneu;
  end;

function f_margeprozneu(ekneu: Extended; lvpneu: Extended): Extended;
  begin
    Result := (1-(ekneu/lvpneu)*100);
  end;

function f_provlvpneu(bpneu: Extended; lvpneu: Extended; ProvSatz: Integer): Extended;
  begin
    Result := (lvpneu-bpneu)*ProvSatz/100;
  end;

function f_bruttolvpneu(lvpneu: Extended; MwSt: Extended): Extended;
  begin
    Result := lvpneu+(lvpneu*MwSt/100);
  end;
 
function f_ekaender(ekneu: Extended; EKAlt: Extended): Extended;
  begin
    Result := (ekneu/EKAlt-1)*100;
  end;

function f_bpaender(bpneu: Extended; BPAlt: Extended): Extended;
  begin
    Result := (bpneu/BPAlt-1)*100;
  end;

function f_lvpaender(lvpneu: Extended; LVPAlt: Extended): Extended;
  begin
    Result := (lvpneu/LVPAlt-1)*100;
  end;

function f_bruttolvpaender(bruttolvpneu: Extended; BruttoLVPAlt: Extended): Extended;
  begin
    Result := (bruttolvpneu/BruttoLVPAlt-1)*100;
  end;

function f_margeEaender(margeEneu: Extended; MargeEAlt: Extended): Extended;
  begin
    Result := (margeEneu-MargeEAlt);
  end;

function f_margeprozaender(margeEneu: Extended; MargeEAlt: Extended): Extended;
  begin
    Result := (margeEneu/MargeEAlt-1)*100;
  end;

function f_provlvpaender(provlvpneu: Extended; ProvLVPAlt: Extended): Extended;
  begin
    Result := (provlvpneu/ProvLVPAlt-1)*100;
  end;

procedure CalcRule01(EKAlt,BPAlt,LVPAlt,BruttoLVPAlt,MargeEAlt, MargeProzAlt, ProvLVPAlt,MwSt: Extended;
   zuschlag, ProvSatz: Integer;
   var ekneu, bpneu,lvpneu,margeEneu,margeprozneu,provlvpneu,bruttolvpneu,bpaender,lvpaender,bruttolvpaender,
   ekaender, margeEaender, margeprozaender, provlvpaender: Extended);
begin
  bpneu := f_bpneu(ekneu, zuschlag);
  lvpneu := f_lvpneu(ekneu);
  margeEneu := f_margeEneu(ekneu, lvpneu);
  margeprozneu := f_margeprozneu(ekneu, lvpneu);
  provlvpneu := f_provlvpneu(bpneu, lvpneu, ProvSatz);
  bruttolvpneu := f_bruttolvpneu(lvpneu, MwSt);
  bpaender := f_bpaender(bpneu, BPAlt);
  lvpaender := f_lvpaender(lvpneu, LVPAlt);
  bruttolvpaender := f_bruttolvpaender(bruttolvpneu, BruttoLVPAlt);
  ekaender := f_ekaender(ekneu, EKAlt);
  margeEaender := f_margeEaender(margeEneu, MargeEAlt);
  margeprozaender := f_margeProzaender(margeEneu, MargeEAlt);
  provlvpaender := f_provlvpaender(provlvpneu, ProvLVPNeu);
end;

end.

//Konstanten:
// EKAlt = cxDBLabel8
// BPAlt = cxDBLabel5
// LVPAlt = cxDBLabel9
// BruttoLVPAlt = cxDBLabel17
// MargeEAlt = cxDBLabel11
// MargeProzAlt = cxDBLabel12
// ProvLVPAlt = cxDBLabel14
// MwSt = cxDBLabel16
// ProvSatz = cxDBLabel13

// Variablen
// ekneu = cxTextEdit1
// zuschlag = cxLookupCombobox1
// bpneu = cxLabel14
// lvpneu = cxTextEdit5
// bruttolvpneu = cxTextEdit4
// margeEneu = cxTextEdit2
// margeprozneu = cxTExtEdit3
// provlvpneu = cxTextEdit6

// + die Variablen, welche die Veränderungen neu gegen alt "anzeigen" sollen
// ekaender = cxLabel15
// bpaender = cxLabel18
// lvpaender = cxLabel19
// bruttolvpaender = cxLabel24     +++ eingentlich obsolet, aberwassolls +++
// margeEaender = cxLabel25
// margeprozaender = cxLabel26
// provlvpaender = cxLabel27
Ich kann leider nicht erkennen, wo ich noch was anpassen müsste.

VG
Emilio

marabu 15. Feb 2006 11:38

Re: komplexe Berechnungen von abhängigen Datenbankfeldern
 
Emilio,

der Compiler meckert wohl zu Recht:

Zitat:

Zitat von Emilio
sowie die Fehlermeldung "nicht genügend wirkliche Parameter"

Die Signatur von CalcRule01() weist 24 Parameter aus, während dein Aufruf nur 15 Parameter mit Werten belegt. So geht das nicht. Noch ein kleiner Tipp: Integer-Variable nenne ich gerne iProzentSatz - das kleine i signalisiert mir den Typ. Diese Vorgehensweise erleichtert mir und anderen das Lesen in fremdem Code.

marabu

Emilio 15. Feb 2006 12:42

Re: komplexe Berechnungen von abhängigen Datenbankfeldern
 
Hi Marabu,

so, habs vervollständigt.

Die Fehlermeldung mit den ungenügenden Parametern ist weg.

Die Meldung "inkompatible Typen Integer und Extended" ist jetzt 2mal da und dazu die Meldung

"Die Typen der tatsächlichen und formalen Var-Parameter müssen übereinstimmen."

Die einzigen beiden Integer-Werte sind [zuschlag] und [provSatz]; ändere ich diese auf Extended (in beiden Units an jeder Stelle) , so compiliert das Programm zwar, allerdings mit den Warnhinweisen, dass die (in Summe 9) Variablen möglicherweise nicht initialisiert worden sind.

Ist es notwendig alle Werte auf Extended einzustellen, selbst wenn sie es originär nicht sind?

Wie initialisiere ich die 9 Variablen?


Wie Du an meinen Fragen erkennen kannst, bewege ich mich auf Neuland.

VG
Emilio

marabu 15. Feb 2006 13:04

Re: komplexe Berechnungen von abhängigen Datenbankfeldern
 
Bei so vielen Parametern in einem Aufruf kann man schonmal die Übersicht verlieren. Es bleibt dir wohl nichts anderes übrig, als jeden Aufruf akribisch unter die Lupe zu nehmen. Jeder Parameter muss mit einem passenden Wert belegt werden, wobei du manchmal auf automatische Typanpassung durch den Compiler hoffen darfst. Einem Extended-Parameter kannst du so ungestraft einen Integer-Wert zuweisen - andersrum geht es nicht.

marabu

Emilio 15. Feb 2006 14:12

Re: komplexe Berechnungen von abhängigen Datenbankfeldern
 
Hi Marabu,

ich werd noch zum Elch: sofern ich einen der originären Werte auf Integer stelle, scheitert die Kompilierung mit der Meldung: "inkompatible blabla ; die Typen der tatsächlichen und formalen Var-Parameter müssen übereinstimmen."

Stelle ich alle Wert auf Extended ein, so kompiliert das Programm mit der bekannten Warnung das 9 Variablen (bpneu, lvpneu, margeEneu, margeprozneu, provlvpneu, bruttolvpneu, bpaender, lvpaender, ekaender) möglicherweise nicht initialisiert worden sind.
Ich kann nicht erkennen, dass ich bei diesen Variablen irgendwie anders vorgegangen bin als bei den anderen.

Das Programm stoppt dann in dem Moment wo das ComboboxOnCloseUp-Ereignis ausgelöst werden soll mit einer Meldung "EInvalidOp" ... 'ungültige Gleitkommaoperation! ..."

Wo schuht der Drück?

VG
Emilio

Emilio 15. Feb 2006 14:27

Re: komplexe Berechnungen von abhängigen Datenbankfeldern
 
Die Fehlermeldung mit den möglicherweise nicht initalisierten Variablen, verschwand, nachdem ich die Reihenfolge der Funktionszuweisungen in der Unit Calc geändert habe ... freu!

Die ungültige Gleitmittel-OP bleibt leider.

VG
Emilio

Emilio 15. Feb 2006 14:45

Re: komplexe Berechnungen von abhängigen Datenbankfeldern
 
Ändere ich die Funktion, auf die die Gleitkomma-Fehlermeldung verweist in eine blödsinnige (bei der keine Division erfolgt), dann passiert bei den nachfolgenden Funktionen, die eine Division enthalten dasselbe. Ändere ich all diese Funktionen in einfache, dann läuft das Programm ohne Fehler, zeigt aber in den Ergebnisfelder nur Nullen an.

Hm, da kanns doch nicht nur an den Formeln liegen, oder?

Emilio 15. Feb 2006 14:59

Re: komplexe Berechnungen von abhängigen Datenbankfeldern
 
:wall: Emilio is'n Dummi! - ekneu ist ja gar keine Variable, sondern in dieser CalcRule eine Konstante ...

dafür sind jetzt möglicherweise wieder 10 Variablen nicht initialisiert und die ERgebnisfelder sind alle "0" - aaaargh!

Emilio 15. Feb 2006 20:07

Re: komplexe Berechnungen von abhängigen Datenbankfeldern
 
@ Marabu,

würde mich mächtig freuen, wenn Du Deinen geschulten Blick noch einmal auf den Code werfen könntest;

Wie durch Geisterhand sind Warnungen mit möglicherweise nichtinitialisierten Variablen verschwunden (vielleicht hat DELPHI erkannt, dass ich veredlungsresistent bin und aufgegeben ...)
Das Programm läuft sauber aber bewirkt nicht das was es sollte. Die Felder die berechneten Werte anzeigen sollen, weisen nach einigem rumprobieren und überlegen immer nur den Wert "0" aus; zwar schön formatiert, aber wertlos. Eigentlich kann es doch nur so sein, dass zum Zeitpunkt der Berechnungen, das Feld [ekneu] oder cxTextEdit1 leer ist - isses aber (zumindest optisch) nicht. Ich komme nicht dahinter!


Delphi-Quellcode:
procedure TForm1.cxLookupComboBox1PropertiesCloseUp(Sender: TObject);

var
  ekneu, bpneu, lvpneu , margeEneu, margeprozneu , provlvpneu, bruttolvpneu, ekaender, bpaender, lvpaender, bruttolvpaender, margeEaender, margeprozaender, provlvpaender,
  EKAlt,BPAlt, LVPAlt, BruttoLVPAlt, MargeEAlt, MargeProzAlt, ProvLVPAlt, MwSt, Provsatz, zuschlag : Extended;

begin
  ekneu := StrToFloat(cxTextEdit1.Text);
  EKAlt := StrToFloat(cxDBLabel8.Caption);
  BPAlt := StrToFloat(cxDBLabel5.Caption);
  LVPAlt := StrToFloat(cxDBLabel9.Caption);
  BruttoLVPAlt := StrToFloat(cxDBLabel17.Caption);
  MargeEAlt := StrToFloat(cxDBLabel11.Caption);
  MargeProzAlt := StrToFloat(cxDBLabel12.Caption);
  ProvLVPAlt := StrToFloat(cxDBlabel14.Caption);
  MwSt := StrToFloat(cxDBLabel16.Caption);
  ProvSatz := StrToFloat(cxDBLabel13.Caption);
  zuschlag := StrToFloat(cxLookupComboBox1.Text);



  CalcRule01(ekneu, bpneu, lvpneu, margeEneu, margeprozneu, provlvpneu, bruttolvpneu, ekaender, bpaender,
  lvpaender, bruttolvpaender, margeEaender, margeprozaender, provlvpaender, EKAlt, BPALT, LVPAlt, BruttoLVPAlt, MargeEAlt, MargeProzAlt,ProvLVPAlt,MwSt,
  ProvSatz, zuschlag);

 
  cxTextEdit1.Text := Format('%m', [ekneu]);
  cxLabel14.Caption := Format('EUR ' + '%8.2f', [bpneu]);
  cxTextEdit5.Text := Format('EUR ' + '%8.2f', [lvpneu]);
  cxTextEdit4.Text := Format('EUR ' + '%8.2f', [bruttolvpneu]);
  cxTextEdit2.Text := Format('EUR ' + '%8.2f', [margeEneu]);
  cxTextEdit3.Text := Format('%5.2f', [margeprozneu]) + '%';
  cxTextEdit6.Text := Format('EUR ' + '%8.2f', [provlvpneu]);
  cxLabel18.Caption := Format('%4.2f', [bpaender]) + '%';
  cxLabel19.Caption := Format('%4.2f', [lvpaender]) + '%';
  cxLabel24.Caption := Format('%4.2f', [bruttolvpaender]) + '%';
  cxLabel25.Caption := Format('%8.2f', [margeEaender]);
  cxLabel26.Caption := Format('%4.2f', [margeprozaender]) + '%';
  cxLabel27.Caption := Format('%4.2f', [provlvpaender]) + '%';

end;
und die Kalk-Unit:

Delphi-Quellcode:
interface

procedure CalcRule01(EKAlt, ekneu, BPAlt,LVPAlt,BruttoLVPAlt,MargeEAlt, MargeProzAlt, ProvLVPAlt, MwSt, ProvSatz, zuschlag: Extended;

   var bpneu,lvpneu, bruttolvpneu, margeEneu, margeprozneu, provlvpneu, ekaender, bpaender, lvpaender, bruttolvpaender,
    margeEaender, margeprozaender, provlvpaender: Extended);

implementation

function f_bpneu(ekneu: Extended; zuschlag: Extended): Extended; forward;
function f_lvpneu(ekneu: Extended): Extended; forward;
function f_margeEneu(ekneu: Extended; lvpneu: Extended):Extended; forward;
function f_margeprozneu(ekneu: Extended; lvpneu: Extended):Extended; forward;
function f_provlvpneu(bpneu: Extended; lvpneu: Extended; ProvSatz: Extended):Extended; forward;
function f_bruttolvpneu(lvpneu: Extended; MwSt: Extended): Extended; forward;
function f_ekaender(ekneu: Extended; EKAlt: Extended): Extended; forward;
function f_bpaender(bpneu: Extended; BPAlt: Extended): Extended; forward;
function f_lvpaender(lvpneu: Extended; LVPAlt: Extended): Extended; forward;
function f_bruttolvpaender(bruttolvpneu: Extended; BruttoLVPAlt: Extended): Extended; forward;
function f_margeEaender(margeEneu: Extended; MargeEAlt: Extended): Extended; forward;
function f_margeprozaender(margeEneu: Extended; MargeEAlt: Extended): Extended; forward;
function f_provlvpaender(provlvpneu: Extended; ProvLVPAlt: Extended): Extended; forward;

function f_bpneu(ekneu: Extended; zuschlag: Extended): Extended;
  begin
    Result := ekneu + (ekneu * zuschlag / 100);
  end;

function f_lvpneu(ekneu: Extended): Extended;
  begin
    Result := ekneu/55*100;
  end;

function f_margeEneu(ekneu: Extended; lvpneu: Extended): Extended;
  begin
    Result := lvpneu-ekneu;
  end;


function f_margeprozneu(ekneu: Extended; lvpneu: Extended): Extended;
  begin
    Result := (1-(ekneu/lvpneu))*100;
  end;

function f_provlvpneu(bpneu: Extended; lvpneu: Extended; ProvSatz: Extended): Extended;
  begin
    Result := (lvpneu-bpneu)*ProvSatz/100;
  end;

function f_bruttolvpneu(lvpneu: Extended; MwSt: Extended): Extended;
  begin
    Result := lvpneu+(lvpneu*MwSt/100);
  end;
 
function f_ekaender(ekneu: Extended; EKAlt: Extended): Extended;
  begin
    Result := (ekneu/EKAlt-1)*100;
  end;

function f_bpaender(bpneu: Extended; BPAlt: Extended): Extended;
  begin
    Result := ((bpneu+BPAlt)-1)*100;
  end;

function f_lvpaender(lvpneu: Extended; LVPAlt: Extended): Extended;
  begin
    Result := (lvpneu+LVPAlt-1)*100;
  end;

function f_bruttolvpaender(bruttolvpneu: Extended; BruttoLVPAlt: Extended): Extended;
  begin
    Result := (bruttolvpneu+BruttoLVPAlt-1)*100;
  end;

function f_margeEaender(margeEneu: Extended; MargeEAlt: Extended): Extended;
  begin
    Result := (margeEneu-MargeEAlt);
  end;

function f_margeprozaender(margeEneu: Extended; MargeEAlt: Extended): Extended;
  begin
    Result := (margeEneu+MargeEAlt-1)*100;
  end;

function f_provlvpaender(provlvpneu: Extended; ProvLVPAlt: Extended): Extended;
  begin
    Result := (provlvpneu+ProvLVPAlt-1)*100;
  end;

procedure CalcRule01(EKAlt, ekneu, BPAlt,LVPAlt,BruttoLVPAlt,MargeEAlt, MargeProzAlt, ProvLVPAlt,MwSt, ProvSatz, zuschlag: Extended;
   
   var bpneu, lvpneu, bruttolvpneu, margeEneu, margeprozneu, provlvpneu, ekaender, bpaender, lvpaender, bruttolvpaender,
   margeEaender, margeprozaender, provlvpaender: Extended);
begin
  bpneu := f_bpneu(ekneu, zuschlag);
  lvpneu := f_lvpneu(ekneu);
  bruttolvpneu := f_bruttolvpneu(lvpneu, MwSt);
  margeEneu := f_margeEneu(ekneu, lvpneu);
  margeprozneu := f_margeprozneu(ekneu, lvpneu);
  provlvpneu := f_provlvpneu(bpneu, lvpneu, ProvSatz);
  ekaender := f_ekaender(ekneu, EKAlt);
  bpaender := f_bpaender(bpneu, BPAlt);
  lvpaender := f_lvpaender(lvpneu, LVPAlt);
  bruttolvpaender := f_bruttolvpaender(bruttolvpneu, BruttoLVPAlt);
  margeEaender := f_margeEaender(margeEneu, MargeEAlt);
  margeprozaender := f_margeProzaender(margeEneu, MargeEAlt);
  provlvpaender := f_provlvpaender(provlvpneu, ProvLVPNeu);
end;

end.

:gruebel:

marabu 15. Feb 2006 22:24

Re: komplexe Berechnungen von abhängigen Datenbankfeldern
 
Hallo Emilio,

ich habe die ersten vier Parameter der Berechnungsvorschrift mit den Aufrufwerten verglichen und dann mein Code-Studium wieder eingestellt, weil die für mich schon nicht zusammen passen. Bitte überprüfe deinen Prozeduraufruf gewissenhaft. Bei der Bereitstellung der Eingabe-Parameter-Werte fällt mir auf, dass du die Rechenwerte aus den Anzeigetexten konvertierst - das ist nicht nötig, da die Datenbank-Feldkomponenten Methoden besitzen, mit denen du direkt den Rechenwert erhältst (AsInteger, AsFloat).

Wenn du deinen Code in Ordnung gebracht hast, dann gib einen Satz Eingabe-Werte und die erwarteten Ergebnisse an - so ist es leichter den Code zu testen. Ich kann leider nicht erkennen, welche Komponenten sich hinter bestimmten Namen verbergen (cxLookupCombo1).

Gute Nacht

marabu

Emilio 16. Feb 2006 10:09

Re: komplexe Berechnungen von abhängigen Datenbankfeldern
 
Hi Marabu,

sorry - ich check's wirklich nicht - kannst Du mir schreiben, was aus Deiner Sicht nicht zusammenpasst? Vielleicht entdecke ich dann des Pudels Kern.

Möglicherweise hilft diese Beschreibung:

Der User gibt einen Wert in cxTextEdit1 (DEVExpress-Kompo) ein = ekneu;
wählt dann einen Zuschlagsatz aus der cxLookupCombobox1 aus = zuschlag;
Daraus errechnet sich über die Funktion/Vorschrift f_bpneu der Wert bpneu.

Alle folgenden Werte bauen auf dem ekneu und den "alten" Werten aus der Datenbank auf.

Nachdem ich jetzt bei der Fehlersuche alle anderen Funktionen auskommentiert habe, stelle ich fest, dass auch dieser erste Schritt schon nicht funktioniert (Ergebnis = 0).

Möglicherweise ist der Aufruf falsch, wenngleich er mit Deinem Beispiel übereinstimmt. Da mir die von Dir freundlicherweise angebotene Lösug vom Verfahren her (noch) fremd ist, tue ich mich verdammt schwer den Fehler zu finden.


VG Emilio

Ferber 16. Feb 2006 10:53

Re: komplexe Berechnungen von abhängigen Datenbankfeldern
 
Hi Emilio !
Zitat:

Zitat von Emilio
Die Meldung "inkompatible Typen Integer und Extended" ist jetzt 2mal da und dazu die Meldung
"Die Typen der tatsächlichen und formalen Var-Parameter müssen übereinstimmen."

Dieser Fehler wird durch den übergeordneten Teil deines Programmes ausgelöst.
Auch dort musst Du den Datentyp auf Extended ändern.
Bei grösseren Anwendungen hat es sich sehr bewährt eine eigene Unit für alle Typdeklarationen, GlobalVariable und Konstanten zu erstellen.
Dort könntest Du zB. definieren
Delphi-Quellcode:
type
  TMyFloat:Extended;
und dann weiter
Delphi-Quellcode:
...
var BruttoLVPAlt, MargeEAlt:TMyFloat;
...
soll der Datentyp später geändert werden, muss dies nur an einer Stelle geschehen.

Zu deinem Berechnungsproblem:
Ziemlich komplexe Sache, schlage eine objektorientiertere Lösung vor.
Kapsle die ganze Berechnung in ein Objekt und statte es mit properties aus.
Dadurch vermeidest du auch die enorme Anzahl an Parametern.
Überlege auch, ob es nicht sinnvoll wäre, die Daten in einem Record zusammenzufassen.
Ich denke dass Du auf dem derzeitigen Weg nur schwer weiterkommst. :gruebel:

Edit: Codebeispiel
Delphi-Quellcode:
interface
type
  TMyFloat = Double;

  TBerechnung = class
  private
    FAltEK, FAltBP, FAltVP:TMyFloat;
    FNeuEK, FNeuBP, FNeuVP:TMyFloat;
    //...
    procedure SetNeuBP(const Value: TMyFloat);
    procedure SetNeuEK(const Value: TMyFloat);
    procedure SetNeuVP(const Value: TMyFloat);
    //...
  protected
    procedure Recalculate;
  public
    property AltEK:TMyFloat read FAltEK write FAltEK;
    property AltBP:TMyFloat read FAltBP write FAltBP;
    property AltVP:TMyFloat read FAltVP write FAltVP;
    property NeuEK:TMyFloat read FNeuEK write SetNeuEK;
    property NeuBP:TMyFloat read FNeuBP write SetNeuBP;
    property NeuVP:TMyFloat read FNeuVP write SetNeuVP;
    //...
  end;

implementation

{ TBerechnung }

procedure TBerechnung.Recalculate;
begin
  // hier die Berechnungen durchführen
  // nur die privaten (F...) variablen setzen - nicht die Properties
  // würde sonst unerwünschte Rekursion ergeben, die mit einer
  // Variablen wie zB: Updating abgefangen werden müsste
end;

procedure TBerechnung.SetNeuBP(const Value: TMyFloat);
begin
  if FNeuBP = Value then exit;
  FNeuBP := Value;
  Recalculate;
end;

procedure TBerechnung.SetNeuEK(const Value: TMyFloat);
begin
  if FNeuEK = Value then exit;
  FNeuEK := Value;
  Recalculate;
end;

procedure TBerechnung.SetNeuVP(const Value: TMyFloat);
begin
  if FNeuVP = Value then exit;
  FNeuVP := Value;
  Recalculate;
end;
Du könntest auf diese Art sogar eine Berechnungskomponente erstellen.

Emilio 16. Feb 2006 13:00

Re: komplexe Berechnungen von abhängigen Datenbankfeldern
 
Hi Ferber,

wow, das hört sich massiv an. Beim ersten Aufruf Deines Beitrags hab ich Dein Code-Beispiel nicht gesehen und dachte gleich, dass das ne Nummer zu hoch für mich ist; so siehts aber schon etwas machbarer für mich aus - Danke!

Hm, Wien soll ja ne schöne Stadt sein; hättest Du im Prinzip mal Interesse und Zeit an Nachhilfe-Unterricht?

VG
Emilio

Emilio 16. Feb 2006 13:02

Re: komplexe Berechnungen von abhängigen Datenbankfeldern
 
@Ferber,

welch unglückliche Formulierung! - Ich meinte selbstverständlich Nachhilfe zu geben !

VG
Emilio

Ferber 16. Feb 2006 15:32

Re: komplexe Berechnungen von abhängigen Datenbankfeldern
 
Hi Emilio !
Hab das Codebeispiel auch erst im Edit angehängt.
Ganz verstehe ich das, was Du mit der Nachhilfe meinst, nicht. :stupid:
Hier im Forum bekommen wir doch alle 'Nachhilfe', wenn's mal nicht weitergeht.
VG Ferber :)
PS: Um meine Zeit ist's leider schlecht bestellt, muss mich um meine Firma kümmern.

Emilio 16. Feb 2006 16:04

Re: komplexe Berechnungen von abhängigen Datenbankfeldern
 
@Ferber,

Betr.: Nachhilfe: habe nebenbei auch eine Compnay zu managen und ebenso ein permanentes Zeitproblem. Tatsächlich aber wäre ich bereit Zeit und Geld in gezielte Hilfestellung für mein Projekt zu investieren, da es mich schlussendlich entlasten soll.

Zurück zum Thema:
habe aus meinem Code alles rausgeworfen, bis auf den ersten Rechenschritt - und siehe da, das Ergebnis von BP ist "0" und der Compiler meldet, dass der Wert der Funktion f_bpneu nie verwendet wird ???
Teufel und die Axt! Ich bin drauf und dran nachma ganz von vorne zu beginnen.

Hast Du ne Idee?

VG Emilio

marabu 17. Feb 2006 09:07

Re: komplexe Berechnungen von abhängigen Datenbankfeldern
 
Hallo Emilio, nur zur Erinnerung:

Zitat:

Zitat von marabu
gib einen Satz Eingabe-Werte und die erwarteten Ergebnisse an


Emilio 17. Feb 2006 11:11

Re: komplexe Berechnungen von abhängigen Datenbankfeldern
 
Hi Marabu,

eigentlich ist es egal, welchen Eingabewert für diese Procedure nimmt.

Aber trotzdem

ekneu = StroFloat(cxTextEdit1.Text) = 1000,00

dann sollte [ekaender] errechnet werden, als OnEditChange in cxTextEdit1 (da das Ergebnis von [ekaender] auf der Form1 in der Zeile von EKAlt und ekneu steht.

EKalt = 1200,00

Also [ekaender] = ((ekneu/EKAlt)-1)*100 = -16,67

dann wählt man aus der cxCombobox1 einen zuschlagsatz [zuschlag] aus z.B.: 10

Also [bpneu] = ekneu+(ekneu*zuschlag/100) = 1100,00

[bpaender] ist dann wie bei [ekaender] ((bpneu/BPAlt)-1)*100.

Als Vorschlag für den Wert [lvpneu] ist die Formel ekneu/55*100 hinterlegt

[lvpaender] ist dann wiederum lvpneu/LVPAlt

usw.

Solange ich alles in einer Unit behalte und nicht in eine "CalcRule" packe (d.h. Funktionen im interface-Abschnitt deklariert, alle Werte mit denen gerechnet wird als Variablen im Implementation-Abschnitt ganz oben, funktioniert alles prima.
Also habe ich vermutlich bei der Umsetzung Deines Vorschlags einen Aufruffehler verbaut (der u.a. bewirkt, dass die Variablen nicht initialisiert werden), den ich nicht finde.

Dennoch würde ich gerne die Trennung in 2 Units bevorzugen, da es übersichtlicher und sicher nützlicher ist, da ja der User auch einen lvpneu( neuer Verkaufspreis) und eine margeprozneu (Marge in % vom neuen Verkaufspreis) als Basisdaten eingeben möchte und alle anderen Felder errechnet werden sollen.

Ich werde jetzt den Code in der UnitMain so fertigmachen und dann den Versuch mit der Trennung neu starten.

Falls Du den Fehler finden solltest - ich freu mich riesig auf Deine Antwort!

VG
Emilio

by the wy: deutsch ist eine furchtbar umständliche Sprache!

marabu 17. Feb 2006 13:18

Re: komplexe Berechnungen von abhängigen Datenbankfeldern
 
Emilio, es ist eigentlich nicht egal - aber da du beim Aufruf der Berechnungsvorschrift ganz fundamentale Fehler machst, ist es auch wieder egal.

Eine gewissenhafte Überprüfung deines Codes hat folgendes zu Tage gefördert:

Delphi-Quellcode:
  CalcRule01(
//  argument           parameter        beispiel
//  ---------------     ----------------  -------------
    ekneu,          // EKalt            
    bpneu,          // EKneu            1000,00
    lvpneu,         // BPalt
    margeEneu,      // LVPalt
    margeprozneu,   // BruttoLVPalt
    provlvpneu,     // MargeEAlt
    bruttolvpneu,   // MargeProzAlt
    ekaender,       // ProvLVPAlt
    bpaender,       // MwSt
    lvpaender,      // ProvSatz
    bruttolvpaender, // zuschlag
// var
    margeEaender,   // bpneu
    margeprozaender, // lvpneu
    provlvpaender,  // bruttolvpneu
    EKAlt,          // margeEneu
    BPALT,          // margeprozneu
    LVPAlt,         // provlvpneu
    BruttoLVPAlt,   // ekaender
    MargeEAlt,      // bpaender
    MargeProzAlt,   // lvpaender
    ProvLVPAlt,     // bruttolvpaender
    MwSt,           // margeEaender
    ProvSatz,       // margeprozaender
    zuschlag        // provlvpaender
  );
Wie du unschwer erkennen kannst, übergibst du die falschen Argumente für die festgelegten Parameter. Wenn du das in Ordnung gebracht hast, dann schreibe in der dritten Spalte unter Beispiel noch die Eingabewerte, mit denen ich testen kann. Ohne konkrete Testdaten mag ich nicht.

Freundliche Grüße vom marabu

Ferber 17. Feb 2006 17:37

Re: komplexe Berechnungen von abhängigen Datenbankfeldern
 
Hi Marabu und Emilio !

Das Problem interessiert mich deshalb, weil ich ähnlichen Themenkreis programmiere.

Habe untersucht was rein und was rausgehen soll, und das tabellarisch dargestellt.

Delphi-Quellcode:
Nur als Quellcode weils da so schön untereinander steht

Rein    : AltEK, AltBP, AltLVP, AltLVPBrutto, AltMarge, AltMargeProz, AltLVPProv,  MwSt, ProvSatz, Zuschlag
Raus    : AendEK, AendBP, AendLVP, AendLVPBrutto, AendMarge, AendMargeProz, AendLVPProv
Raus/Rein: NeuEK, NeuBP, NeuLVP, NeuLVPBrutto, NeuMarge, NeuMargeProz, NeuLVPProv
Die Neu...-Varaiblen sollen ja Ein/Ausgabe-Felder werden, was sie ja bisher noch nicht sind,
und dann wird das eigentliche Dilemma erst beginnen, da ja die übrigen Felder aktualisiert werden müssen.

@Emilio: Du wirst um das Objektorientierte und Properties IMHO nicht herumkommen.

Beispielsweise sollten ja alle Neu...-Variablen auf den Wert der Alt-Variablen initialisiert werden.
Beim Verändern einzelner Neu...-Werte mussen unterschiedlichste Berechnungen durchgeführt werden.

Schlimm wirds besonders dann, wenn noch die Änderungsfelder Ein/Ausgabefelder werden sollen.

Na viel Spass :mrgreen:

marabu 17. Feb 2006 20:16

Re: komplexe Berechnungen von abhängigen Datenbankfeldern
 
Hallo Otto,

warum willst du ein rein funktionales Problem unbedingt objekt-orientiert angehen? Hast du dir schon überlegt, wie du deinen Beispiel-Code so erweiterst, dass er benutzerdefinierte Zielgrößen berücksichtigt?

Freundliche Grüße vom marabu

Emilio 17. Feb 2006 22:53

Re: komplexe Berechnungen von abhängigen Datenbankfeldern
 
Hi @all,

so funzt es, wenn alles in der UnitMain untergebracht ist:

Delphi-Quellcode:

interface

...

    procedure DBLookupComboBox1CloseUp(Sender: TObject);                  
    procedure cxTextEdit1KeyPress(Sender: TObject; var Key: Char);
    procedure cxLookupComboBox1PropertiesCloseUp(Sender: TObject);
    function f_bpneu(ekneu: Extended; zuschlag: Extended): Extended;
    function f_ekaender(ekneu: Extended; EKAlt: Extended): Extended;
    function f_bpaender(bpneu: Extended; BPAlt: Extended): Extended;
    function f_lvpneu(ekneu: Extended): Extended;
    function f_lvpaender(lvpneu: Extended; LVPAlt: Extended): Extended;
    function f_bruttolvpneu(lvpneu: Extended; MwSt: Extended): Extended;
    function f_bruttolvpaender(bruttolvpneu: Extended; BruttoLVPAlt: Extended): Extended;
    function f_margeEneu(ekneu: Extended; lvpneu: Extended): Extended;
    function f_margeEaender(margeEneu: Extended; MargeEAlt: Extended): Extended;
    function f_margeprozneu(ekneu: Extended; lvpneu: Extended): Extended;
    function f_margeprozaender(margeEneu: Extended; MargeEAlt: Extended): Extended;
    function f_provlvpneu(bpneu: Extended; lvpneu: Extended; ProvSatz: Extended): Extended;
    function f_provlvpaender(provlvpneu: Extended; ProvLVPAlt: Extended): Extended;

...

implementation

var
  ekneu, zuschlag, bpneu, EKAlt, ekaender, BPAlt, bpaender, lvpneu, LVPAlt, lvpaender, bruttolvpneu,
  MwSt, BruttoLVPAlt, bruttolvpaender, margeEneu, MargeEAlt, margeEaender, margeprozneu,
  margeprozaender, provlvpneu, ProvSatz, provlvpaender, ProvLVPAlt : Extended;

...

function TForm1.f_bpneu(ekneu: Extended; zuschlag: Extended): Extended;
  begin
    Result := ekneu + (ekneu * zuschlag / 100);
  end;

function TForm1.f_ekaender(ekneu: Extended; EKAlt: Extended):Extended;
  begin
    Result := ((ekneu/EKAlt)-1)*100;
  end;

function TForm1.f_bpaender(bpneu:Extended; BPAlt: Extended):Extended;
  begin
    Result := ((bpneu/BPAlt)-1)*100;
  end;

function TForm1.f_lvpneu(ekneu: Extended):Extended;
  begin
    Result := ekneu/55*100;
  end;

function TForm1.f_lvpaender(lvpneu: Extended; LVPAlt: Extended): Extended;
  begin
    Result := lvpneu-LVPAlt;
  end;

function TForm1.f_bruttolvpneu(lvpneu: Extended; MwSt: Extended): Extended;
  begin
    Result := lvpneu + (lvpneu*MwSt/100);
  end;

function TForm1.f_bruttolvpaender(bruttolvpneu: Extended; BruttoLVPAlt: Extended):Extended;
  begin
    Result := ((bruttolvpneu/BruttoLVPAlt)-1)*100;
  end;

function TForm1.f_margeEneu(ekneu: Extended; lvpneu: Extended): Extended;
  begin
    Result := lvpneu-ekneu;
  end;

Function TForm1.f_margeEaender(margeEneu: Extended; MargeEAlt: Extended): Extended;
  begin
    Result := margeEneu-MArgeEAlt;
  end;

Function TForm1.f_margeprozneu(ekneu: Extended; lvpneu: Extended): Extended;
  begin
    Result := (1-(ekneu/lvpneu))*100;
  end;

function TForm1.f_margeprozaender(margeEneu: Extended; MargeEAlt: Extended): Extended;
  begin
    Result :=((margeEneu/MargeEAlt)-1)*100;
  end;

function TForm1.f_provlvpneu(bpneu: Extended; lvpneu: Extended; ProvSatz: Extended): Extended;
  begin
    Result := (lvpneu-bpneu)*ProvSatz/100;
  end;

function TForm1.f_provlvpaender(provlvpneu: Extended; ProvLVPAlt: Extended): Extended;
  begin
    Result := ((provlvpneu/ProvLVPAlt)-1)*100;
  end;



 
procedure TForm1.cxLookupComboBox1PropertiesCloseUp(Sender: TObject);

begin                                                               Beispielwerte
  ekneu := StrToFloat(cxTextEdit1.Text);                            1000,00 
  zuschlag := StrToFloat(cxLookupComboBox1.Text);                   10,00
  bpneu := f_bpneu(ekneu, zuschlag);                                1100,00
  EKAlt := qrypli.Fieldbyname('EK').AsFloat;                        900,00
  ekaender := f_ekaender(ekneu, EKalt);                             11,11 (%)
  BPAlt := qrypli.Fieldbyname('BP').AsFloat;                        980,00
  bpaender := f_bpaender(bpneu, BPAlt);                             12,24 (%)  
  lvpneu := f_lvpneu(ekneu);                                        1818,18
  LVPAlt := qrypli.Fieldbyname('LVP').AsFloat;                      1600,00
  lvpaender := f_lvpaender(lvpneu, LVPAlt);                         218,18
  MwSt := qrypli.Fieldbyname('MwStSatz').AsFloat;                   16,00
  bruttolvpneu := f_bruttolvpneu(lvpneu, MwSt);                     2109,09 
  BruttoLVPAlt := qrypli.Fieldbyname('BruttoLVP').AsFloat;          1856,00
  bruttolvpaender := f_bruttolvpaender(bruttolvpneu, BruttoLVPAlt); 13,64 (%)
  margeEneu := f_margeEneu(ekneu, lvpneu);                          818,18
  MargeEAlt := qrypli.Fieldbyname('MARGE').AsFloat;                 700,00
  margeEaender := f_margeEaender(margeEneu, MargeEAlt);             118,18 
  margeprozneu := f_margeprozneu(ekneu, lvpneu);                    45,00 (%)
  margeprozaender := f_margeprozaender(margeEneu, MargeEAlt);       16,88 (%)
  ProvSatz := qrypli.Fieldbyname('PSatz').AsFloat;                  5,00
  provlvpneu := f_provlvpneu(bpneu, lvpneu, ProvSatz);              35,91
  ProvLVPAlt := qrypli.Fieldbyname('ProvLVP').AsFloat;              31,00 
  provlvpaender := f_provlvpaender(provlvpneu, ProvLVPAlt);         15,84 (%)


  cxTextEdit1.Text := Format('%8.2f', [ekneu]);
  cxLabel14.Caption := Format('EUR ' + '%8.2f', [bpneu]);
  cxLabel15.Caption := Format('%4.2f', [ekaender]) + '%';
  cxLabel18.Caption := Format('%4.2f', [bpaender]) + '%';
  cxTextEdit5.Text := Format('EUR ' + '%8.2f', [lvpneu]);
  cxLabel19.Caption := Format('%m', [lvpaender]);
  cxTextEdit4.Text := Format('EUR ' + '%8.2f', [bruttolvpneu]);
  cxLabel24.Caption := Format('%4.2f', [bruttolvpaender]) + '%';
  cxTextEdit2.Text := Format('EUR ' + '%8.2f', [margeEneu]);
  cxLabel25.Caption := Format('%m', [margeEaender]);
  cxTextEdit3.Text := Format('%5.2f', [margeprozneu]) + '%';
  cxLabel26.Caption := Format('%4.2f', [margeprozaender]) + '%';
  cxTextEdit6.Text := Format('EUR ' + '%8.2f', [provlvpneu]);
  cxLabel27.Caption := Format('%4.2f', [provlvpaender]) + '%';
unschön ist noch :
- das Feld cxTextEdit1, in welches der ekneu vom user eingetragen wird, sollte nach dem Eintragen formatiert werden ('EUR' + '%8.2f'); krieg ich aber(noch) nicht hin, da ich diesen Wert ja roh brauche.
- der Wert [ekaender] sollte besser als OnChange- oder OnEditValueChanged-Event(in cxTextEdit1) erscheinen - also aus der Combobox-procedure raus - krieg ich auch noch hin ...

jetzt kommt's:

Wie bereits erwähnt, kann es sein, dass der User mit dem lvpneu nicht einverstanden ist und diesen überschreibt. Dann sollten sich 10 Werte ändern (alle außer (ekneu), (bpneu), (ekaender), [bpaender]). Womöglich will er aber auch eine "fixe" Marge vorgeben und nur einen lvpneu ...

Also ich erkenne die Anforderungen, den Kram aufzusplitten als notwendig an.

Als erstes versuche ich jetzt den Code so umzustricken, dass er dem Beispiel von Marabu folgt und ich erkenne was ich im ersten Anlauf versaubeutelt habe.

Der Saft sei mit mir!

VG
Emilio

Emilio 18. Feb 2006 21:19

Re: komplexe Berechnungen von abhängigen Datenbankfeldern
 
:party: :dancer: :cheers: Es funzt!!!

Hi Marabu, hi Ferber,

mit ordentlich Konzentration und reichlich Kaffee habe ich es geschafft, das Beispiel von Marabu richtig zu übersetzen - keine Warnhinweise, keine Fehlermeldungen und alle Eregebnisse da und richtig - freu!

@Marabu,
gehe ich richtig in der Annahme, dass ich für die anderen bereits erwähnten Möglichkeiten (also User hat andere Ausgangswerte als den neuen EK oder will Anpassungen überdie EditFelder vornehmen) weitere CalcRules erstelle oder wäre das zu einfach ...?

@Ferber,
wenngleich Marabu Deinen Vorschlag für 'unangemessen' hält, könntest Du Deinen Weg etwas weiter ausführen?

Schönes Wochenende und vielen herzlichen Dank für Eure Hilfe

VG
Emilio

thomasw 18. Feb 2006 21:33

Re: komplexe Berechnungen von abhängigen Datenbankfeldern
 
sorry, bitte löschen...

Emilio 18. Feb 2006 21:54

Re: komplexe Berechnungen von abhängigen Datenbankfeldern
 
Zitat:

Zitat von thomasw
sorry, bitte löschen...


Sorry - was löschen ?

marabu 19. Feb 2006 17:03

Re: komplexe Berechnungen von abhängigen Datenbankfeldern
 
Hallo Emilio,

Zitat:

Zitat von Emilio
gehe ich richtig in der Annahme, dass ich für die anderen bereits erwähnten Möglichkeiten (also User hat andere Ausgangswerte als den neuen EK oder will Anpassungen über die EditFelder vornehmen) weitere CalcRules erstelle?

du brauchst keine neue Berechnungsvorschrift, wenn sich nur die Eingangswerte ändern. Nur wenn deine Funktionen anders verkettet werden ergibt sich daraus auch eine andere Berechnungsvorschrift.

Zur Verdeutlichung ein einfaches Beispiel: Ein Quader hat drei Seiten (a,b, und c) und ein Volumen V. Aus jeweils drei Eingabewerten lässt sich der vierte berechnen. Es ergeben sich vier triviale Rechenvorschriften. Trivial, weil alle Vorschriften nur von Konstanten abhängig sind:
  • V = f(a,b,c) = a * b * c
  • a = f(V,b,c) = V / (b * c)
  • b = f(V,a,c) = V / (a * c)
  • c = f(V,a,b) = V / (a * b)
Und was Ottos Vorschlag mit den Objekten angeht, so möchte ich folgendes klarstellen, weil es vielleicht nicht richtig rüber gekommen ist: Ein nicht triviales Kalkulationsmodell besteht aus einer Vielzahl von Berechnungsvorschriften (v) und modell-spezifischen Verkettungen (v1 = f1 nach f2 nach f3; v2 = f4 nach f2 nach f3; etc.). Dieses funktionale Gebilde kommt sehr gut ohne Objekt-Orientierung aus. Ganz anders die dazu passende Benutzerschnittstelle. Mit zunehmender Komplexität des Modells wird da ein OO-Ansatz unentbehrlich. Vielleicht wollte Otto darauf hinweisen und ich habe ihn nicht gleich verstanden. Es täte mir leid.

Freundliche Grüße vom marabu

Ferber 19. Feb 2006 20:50

Re: komplexe Berechnungen von abhängigen Datenbankfeldern
 
Liste der Anhänge anzeigen (Anzahl: 2)
Ja, manchmal kann das ziemlich komplex werden.

Nachdem ich das Ganze überschlafen hab dachte ich mir schon,
dass der OO-Ansatz doch ein 'mit Kanonen auf Spatzen schiessen' ist. :?

Eine grosse Mühsal ist halt die ganze Herumformatiererei.

Ich hab deshalb in meinem Komponentenfundus gekramt, was gefunden, und Überarbeitet.
Dabei hab ich natürlich ersteinmal alles Kaputtgemacht :stupid: bevor's wieder gelaufen ist,
aber jetzt haben die Edits auch Label (von BDS abgespranzt).
Natürlich bin ich nachher draufgekommen dass ich den falschen Vorfahren erwischt habe,
sollte vielleicht endlich mal zumindest auf D7 umsteigen, aber so funzts wenigstens auch in D5.

Es ist ein Set von EditKomponenten, die weit mehr können als TEdit.
Vor allem gibt's die Eigenschaft 'Value', die direkt zugewiesen werden kann, der Text wird Formatiert.

Ich stell das hier als Open-Source herein, bitte ausprobieren und testen.
Ein Testbeispiel ist auch dabei.

Liebe Grüsse vom 'Ferber' :coder:

Emilio 21. Feb 2006 09:18

Re: komplexe Berechnungen von abhängigen Datenbankfeldern
 
@Marabu,

Zitat:

Ganz anders die dazu passende Benutzerschnittstelle. Mit zunehmender Komplexität des Modells wird da ein OO-Ansatz unentbehrlich.
Benutzerschnittstelle - das ist das Stichwort:

Es gibt ingesamt 5 Edit-Felder in die der User Werte eingeben könnte (ekneu, lvpneu, bruttolvpneu, MargeE und Marge%).

Der ekneu kann z.B. über 3 Wege zustande kommen:

- User-Eintrag im ekneu Edit-Feld
- User-Eintrag im lvpneu-Feld und MargeE- oder Marge%-Feld (Berechnung)
- User-Eintrag im bruttolvpneu-Feld und MargeE- oder Marge%-Feld (Berechnung)

der lvp kann z.B. über 5 Wege zustande kommen:
- User-Eintrag im lvpneu Edit-Feld
- User-Eintrag im ekneu-Feld + Auswahl des zuschlag aus der Combobox (Auto-Vorschlag wie in CalcRule01)
- User-Eintrag im bruttolvp-Feld (Berechnung)
- User-Eintrag im ekneu-Feld und MargeE- oder Marge%-Feld (Berechnung)
- User-Eintrag im bruttolvpneu-Feld und MargeE- oder Marge%-Feld (Berechnung)

Die 7 Werte, welche die Änderungen neu gegen Alt ausdrücken (ekaender, xyaender, etc.) werden eigentlich immer dann benötigt, wenn zum passenden Alt-Wert ein neu-Wert eingegeben oder errechnet und angezeigt wird.

Mit den genannten Wegen decke ich jedoch nur die "primär"-Eingabe ab; Nicht erfasst sind Änderungen, die der User nach der Primär-Eingabe vornehmen möchte (z.B. den bruttolvpneu runden/glätten, die Marge prozentual anpassen, etc.).
Das hieße, nach der Ergänzung des Codes für die primär-Eingaben noch 7 onChange-Events mit unterschiedlichen "Calcrules" bauen - oder nicht? Irgendwie werde ich das Gefühl nicht los, dass ich das bisherige Konstrukt zerfleddern muß, um den User-Wünschen gerecht zu werden. Ich grübel weiter.

Falls jemand noch 'n Tipp hat - ich freue mich!

VG
Emilio

Ferber 21. Feb 2006 13:13

Re: komplexe Berechnungen von abhängigen Datenbankfeldern
 
Das Thema ist ja ein richtiger Dauerbrenner - :coder:


Zitat:

Zitat von Emilio
Der ekneu kann z.B. über 3 Wege zustande kommen:

- User-Eintrag im ekneu Edit-Feld
- User-Eintrag im lvpneu-Feld und MargeE- oder Marge%-Feld (Berechnung)
- User-Eintrag im bruttolvpneu-Feld und MargeE- oder Marge%-Feld (Berechnung)

der lvp kann z.B. über 5 Wege zustande kommen:
- User-Eintrag im lvpneu Edit-Feld
- User-Eintrag im ekneu-Feld + Auswahl des zuschlag aus der Combobox (Auto-Vorschlag wie in CalcRule01)
- User-Eintrag im bruttolvp-Feld (Berechnung)
- User-Eintrag im ekneu-Feld und MargeE- oder Marge%-Feld (Berechnung)
- User-Eintrag im bruttolvpneu-Feld und MargeE- oder Marge%-Feld (Berechnung)

Die 7 Werte, welche die Änderungen neu gegen Alt ausdrücken (ekaender, xyaender, etc.) werden eigentlich immer dann benötigt, wenn zum passenden Alt-Wert ein neu-Wert eingegeben oder errechnet und angezeigt wird.

Mit den genannten Wegen decke ich jedoch nur die "primär"-Eingabe ab; Nicht erfasst sind Änderungen, die der User nach der Primär-Eingabe vornehmen möchte (z.B. den bruttolvpneu runden/glätten, die Marge prozentual anpassen, etc.).
Das hieße, nach der Ergänzung des Codes für die primär-Eingaben noch 7 onChange-Events mit unterschiedlichen "Calcrules" bauen - oder nicht? Irgendwie werde ich das Gefühl nicht los, dass ich das bisherige Konstrukt zerfleddern muß, um den User-Wünschen gerecht zu werden. Ich grübel weiter.

Jetzt sieht die Sache schon recht übersichtlich aus !

@Emilio: Stell Dir nun vor, Du müsstest das Ganze nur in 7 Formeln kleiden, die alle anderen Variablen berechnen.
Falls Du auch der Meinung bist, dass das simpel ist, dann schau doch endlich meine Komponenten an !
Das sind quasi Variablen, die Dir den ganzen restlichen Schnickschnack abnehmen.
Nenne diese zB. EKNeu und verwende sie als EKNeu.Value.

Kurzbeschreibung aus den Units herauskopiert:

Delphi-Quellcode:
{ Unit MyEditPrim erweitert das etwas dümmliche TLabeledEdit um Eigenschaften und Ereignisse,
  die in der Praxis des Programmierens IMHO notwendig sind.

  TEditPrim ist Vorfahre für weitere, spezialisiertere EditKomponenten (siehe Unit MyEdit)

  Erweiterungen:

  property Alignment   Ausrichtung des Textes taLeftJustify, taCenter, taRightJustify

  property RedValues   Negative Werte werden rot dargestellt

  property ReturnIsTab Eingabetaste ist wie Tab

  property OnChange    Änderung des Verhaltens. Wird nur durch Enter, Tab oder Verlassen des
                        Edits ausgelöst, nicht mehr bei jeder Zeichneingabe,
                        und auch dann nur, falls der Wert geändert wurde.
                        Validierung der Eingabe möglich.

  property OnIniData   Wird Aufgerufen um Variablen mit Value belegen zu können.

  property OnDrwData   Wird vor dem Zeichnen aufgerufen und erlaubt Änderungen von Farbe und Font

  Taste ESC stellt den ursprünglichen Wert des Feldes wieder her.
}
{ unit MyEdit leitet vom erweiterten TEditPrim, die spezialisierten Editfelder

  TEditString, TEditInteger, TEditFloat, TEditCurr, TEditProz und TEditDate ab.

  Basisverhalten siehe: Unit MyEditPrim.

  Jedes diese Editfelder hat die zusätzliche Eigenschaft 'Value',
  die dem DatenTyp entspricht.

  Nachkommastellen bei den entsprechend Datentypen sind einstellbar.
  Vorgabe bei Float und Currency: 2, bei Prozent: 0

  Zuweisungen zur Eigenschaft Value lösen das Ereignis OnChange NICHT aus.
  Zuweisungen zur Eigenschaft Text lösen das Ereignis OnChange nach wie vor aus.

  Zusätzliche Eigenschaft NullValues - wie Excel Nullwerte anzeigen, Vorgabe false.

  Zusätzliches Ereignis OnInitData ermöglicht das initialisieren von Variablen.

  Validierung kann im Ereignis OnChange durchgeführt werden.

  TEditPrim wurde in separate Unit extrahiert, um die Übersichtlichkeit zu erhöhen.

  Die Erweiterung um weitere Datentypen ist in Unit MyEdit sehr einfach.
}
Edit: Die Komponenten gibts hier: EditKomponenten für die Praxis

Mit freundlichen Grüssen, Otto.


Alle Zeitangaben in WEZ +1. Es ist jetzt 00:46 Uhr.
Seite 1 von 2  1 2      

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