Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   DBEdits rufen sich gegenseitig auf (https://www.delphipraxis.net/179533-dbedits-rufen-sich-gegenseitig-auf.html)

süden 13. Mär 2014 12:43

DBEdits rufen sich gegenseitig auf
 
Hallo,

es werden: Anfangszeit(TTime) | Stunden(Int) | Minuten(Int) | Endezeit(TTime) berechnet.

Im Form ist ein cxGrid(DevEx) und in einem Detailfeld das Ganze noch mal in Editfeldern.
Zeiten in cxDBDateTimeEdit, Stunden/Minuten in cxDBSpinEdit.

Die Änderungen in einem der Edits oder im Grid sollen dem Benutzer sofort angezeigt werden, das heißt, sie werden in "onEditValueChanged" berechnet und den anderen Èdits zugewiesen.
Es stehen OnChange, OnEditValueChanged und OnValidate zur Verfügung.

Jetzt ist das Problem, dass sie sich gegenseitig aufrufen = Endlosschleife.

Mir fällt nichts ein, wie ich das unterbinen kann.
Wenn ich nur das Grid benutze und die Berechnungen aus den Edits rausnehme dann geht's.

Nersgatt 13. Mär 2014 12:52

AW: DBEdits rufen sich gegenseitig auf
 
Guck Dir mal in der Hilfe .LockChangeEvents der Controls an.

Sir Rufo 13. Mär 2014 13:09

AW: DBEdits rufen sich gegenseitig auf
 
Da du die Berechnung vom Kontext abhängig machst
(z.B.
  • Anfang: Ende = Anfang - Dauer
  • Ende: Dauer = Anfang - Ende
  • Dauer: Ende = Anfang + Dauer
)
musst du dir wohl oder übel auch den Kontext merken und nicht einfach nur drauf los rechnen ;)
Den Kontext (aktives Feld) bekommt man aber auch über Delphi-Referenz durchsuchenTForm.ActiveControl

Eine andere Möglichkeit wäre, die Berechnung entsprechend zu unterbinden, wenn man schon berechnet:
Delphi-Quellcode:
type
  TForm1 = class( TForm )
    Anfang_SpinEdit : TSpinEdit;
    Ende_SpinEdit : TSpinEdit;
    Interval_SpinEdit : TSpinEdit;
    // alle 3 Felder rufen bei OnChange diese Methode auf
    procedure ControlChange( Sender : TObject );
  private
    FCalculating : Boolean;
    procedure DoCalculate( Context : TObject );
  public
    { Public-Deklarationen }
  end;

var
  Form1 : TForm1;

implementation

{$R *.dfm}
{ TForm1 }

procedure TForm1.ControlChange( Sender : TObject );
begin
  // Wenn die Berechnung schon läuft, dann wieder raus hier
  if FCalculating then
    Exit;

  // Berechnungs-Flag setzen
  FCalculating := True;
  try
    // Berechnung durchführen
    DoCalculate( Sender );
  finally
    // Berechnungs-Flag entfernen
    FCalculating := False;
  end;
end;

procedure TForm1.DoCalculate( Context : TObject );
begin
  // abhängig vom Context die Berechnung durchführen
  if Context = Anfang_SpinEdit then
  begin
    Ende_SpinEdit.Value := Anfang_SpinEdit.Value + Interval_SpinEdit.Value;
  end
  else if Context = Ende_SpinEdit then
  begin
    Interval_SpinEdit.Value := Ende_SpinEdit.Value - Anfang_SpinEdit.Value;
  end
  else if Context = Interval_SpinEdit then
  begin
    Ende_SpinEdit.Value := Anfang_SpinEdit.Value + Interval_SpinEdit.Value;
  end;
end;

Jumpy 13. Mär 2014 14:20

AW: DBEdits rufen sich gegenseitig auf
 
Mal doof gefragt (denn ich hab wahrsch. die Frage nur halb verstanden): Wenn das doch DBEdits usw. sind. Wenn ich da irgendwas ändere, ändert das nicht auch die darunterliegende Datasource, so dass die Änderungen auch in anderen Edits, die dasselbe anzeigen, autom. angezeigt werden?

Alternativ zu dem sicher sinnvollen Ansatz von Sir Rufo kann man auch immer die Eventhandler abschalten, um so Zirkelgeschichten aufzulösen und dann nachher wieder anschalten.

Sir Rufo 13. Mär 2014 14:28

AW: DBEdits rufen sich gegenseitig auf
 
Zitat:

Zitat von Jumpy (Beitrag 1251863)
Mal doof gefragt (denn ich hab wahrsch. die Frage nur halb verstanden): Wenn das doch DBEdits usw. sind. Wenn ich da irgendwas ändere, ändert das nicht auch die darunterliegende Datasource, so dass die Änderungen auch in anderen Edits, die dasselbe anzeigen, autom. angezeigt werden?

Aber direkt beim Tippen stehen die noch nicht im DataSource zur Verfügung ...
Zitat:

Zitat von Jumpy (Beitrag 1251863)
Alternativ zu dem sicher sinnvollen Ansatz von Sir Rufo kann man auch immer die Eventhandler abschalten, um so Zirkelgeschichten aufzulösen und dann nachher wieder anschalten.

Geht auch, halte ich aber für schwerer zu kontrollieren als so ein Flag.

Prominentes Beispiel ist Delphi-Referenz durchsuchenTComponent.ComponentState, da würde man sich nur die Haare raufen, wenn man da ständig die Events entfernt und wieder zuweist. Da ist die Steuerung über ein Flag (bzw. ein Flag-Set) wesentlich unkomplizierter und der Code wird erheblich lesbarer, weil man dann schon sieht, wann bestimmte Codeteile nicht ausgeführt werden. Das sieht man nicht, wenn an irgendeiner Stelle der Event mal eben ausgehebelt wird.

süden 14. Mär 2014 14:01

AW: DBEdits rufen sich gegenseitig auf
 
Sir Rufo, Dein Vorschlag (Kontext) hat funktioniert. Danke.

Allerdigs nicht mit dem Eintrag der Werte in die Value-Eigenschaft, sondern direkt in die Datenbank (FieldByName ...).
Als angenehmer Nebeneffekt brauche ich die Berechnungen nicht im Grid zu wiederholen.
Über die Datenbank werden Grid und Edits getriggert, egal ob ich die Edits verändere oder die Werte im Grid, die Funktionen laufen immer in den Edits ab.

(Habt ihr meine Erklärung verstanden? Ich kanns nicht besser erklären.)

Nochmal Danke.

Delphi-Quellcode:
...
    // STUNDEN geändert
    else if TimeContext = sedStunden then
    begin
      dBegin := FieldByName('TimeBegin').AsFloat;
(*      dStd  := sedStunden.EditValue;*)
      dStd  := FieldByName('Anzahl_std').AsInteger;
      iMin  := FieldByName('Anzahl_min').AsInteger;

      x := (dStd/24) + (iMin / 1440); // Zeitwerte dezimal 24:00 = 1 , 12:00 = 0.5
      dEnde := dBegin + x;
      x := ((dStd*60) + iMin)/60;     // Summe in Minuten /60 = Summe in Stunden
      iStd  := Trunc(x);
      iMin  := Round(Frac(x) * 60);

      if State IN [dsInsert,dsEdit] then
      Begin
        FieldByName('TimeEnde').AsFloat := dEnde;
        FieldByName('Anzahl_std').AsInteger := iStd;
        FieldByName('Anzahl_min').AsInteger := iMin;
      End;
    end ...


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