Variabler Zugriff auf Komponenten aus anderer unit

Für Fragen von Einsteigern und Programmieranfängern...
Antworten
musicto
Beiträge: 5
Registriert: Do 11. Apr 2024, 07:32

Variabler Zugriff auf Komponenten aus anderer unit

Beitrag von musicto »

Hallo zusammen,

als Beispiel:
Ich habe eine UNIT1 mit einer Form (Form1) und einem DBDateEdit (Dat1) Feld.
Aus meiner Unit2 kann ich über form1.dat auf die Eigenschaften dieser Komponente zugreifen.
So weit so gut.
Folgender Code:

Code: Alles auswählen

 
 var
  mydate: TDateTime; 
 ...
 with form1 do
    begin
    	...
	Dat1.Date:=mydate;
	...
    end;             
 
funktioniert,
aber warum bekomme ich bei diesem Code eine Exception?:

Code: Alles auswählen

 
 var
  mydate: TDateTime; 
  cname : string;
 ...
 ...
 cname :='Dat1';
 with form1 do
    begin
    	...
	TDBDateEdit(cname).Date:=mydate;
	...
    end;             
 
Vielen Dank und Grüße

Sascha

Benutzeravatar
theo
Beiträge: 10927
Registriert: Mo 11. Sep 2006, 19:01

Re: Variabler Zugriff auf Komponenten aus anderer unit

Beitrag von theo »

Wieso denkst du, dass du den String (cname) einfach auf ein TDBDateEdit typecasten kannst?
Das kracht natürlich.
Aus welchem Grund versuchst du das?

CCRDudeLaz
Beiträge: 54
Registriert: Do 25. Jan 2024, 08:33
OS, Lazarus, FPC: Win/macOS (L trunk FPC trunk)
CPU-Target: 32+64

Re: Variabler Zugriff auf Komponenten aus anderer unit

Beitrag von CCRDudeLaz »

Weil ein String keine Komponente ist.

Du kannst in der Liste der Components (iterieren mit ComponentCount) diejenige mit dem gewünschten Namen suchen, aber X(A) macht einfach einen Typecast. Mit dem String findet keine automatische Suche statt.

Darüber hinaus macht es vielleicht mehr Sinn, das Control der Funktion / Methode in Unit2 mitzuteilen, anstatt über die globable Variable Form1 zu gehen.

musicto
Beiträge: 5
Registriert: Do 11. Apr 2024, 07:32

Re: Variabler Zugriff auf Komponenten aus anderer unit

Beitrag von musicto »

Hallo,

ich habe ca 20 DBDateEdit Komponenten auf meiner Form1.
Beispielhaft:
Dat1_BEG, Dat2_END
Dat2_BEG, Dat2_END
Dat3_BEG, Dat3_END
...
...

Diese definieren ein Start und Endedatum einer bestimmten fachlichen Aktion.

Mein Ziel ist im OnEditingDone der Startdatum Komponenten auf folgende Procedure meiner Unit2 zuzugreifen um mein Endedatum automatisch vorzubelegen.

Code: Alles auswählen

procedure setEndDate(Sender: TObject; Months: integer);
var
  cName: string;
  mydate: TDateTime;
begin
  mydate := TDBDateEdit(Sender).Date;
  mydate := EndOfTheMonth(IncMonth(mydate, 3));
  cName := TDBDateEdit(Sender).Name;
  cName := StringReplace(cName, 'BEG', 'END', [rfReplaceAll]);
  try
    with form1 do
    begin
        TDBDateEdit(cName).Date := mydate;
    end;
  except
  end;
end;   
 

Grüße
Sascha

Benutzeravatar
Zvoni
Beiträge: 408
Registriert: Fr 5. Jul 2024, 08:26
OS, Lazarus, FPC: Windoof 10 Pro (Laz 2.2.2 FPC 3.2.2)
CPU-Target: 32Bit
Wohnort: BW

Re: Variabler Zugriff auf Komponenten aus anderer unit

Beitrag von Zvoni »

Wieso hast du das überhaupt in einer Unit2?
Code, welcher ausschliesslich einen Effekt auf eine Komponente in einer Unit hat gehört in diese Unit (Nicht in eine separate Unit).
Ausnahme: Du hast weitere Forms, welche auch den gleichen Code nutzen wollen.
In dem Fall würde ich die aufrufende Form als "var"-Argument an die Prozedur weiterreichen.

EDIT: Was man auch machen kann:
Gib allen TDBDateEdit "saubere" Tags!
DAT1_BEG.Tag:=0;
DAT1_END.Tag:=1;
DAT2_BEG.Tag:=2;
DAT2_END.Tag:=3;
usw.
im OnEditingDone bekommst du den "Sender"
Ist das Tag des Senders "gerade" ist es dein Startdatum, und dieses Sender.Tag+1 ist das passende End-Datum.....
Ist das Tag des Senders "ungerade" ist es dein Enddatum, und dieses Sender.Tag-1 ist das passende Start-Datum.....

Code: Alles auswählen

If Not Odd(TDBDateEdit(Sender).Tag) Then Writeln('Tag ist gerade') Else Writeln('Tag ist ungerade');
Wenn du jetzt vorher alle 20 DBDateEdit in einem Array[0..19] Of TDBDateEdit eingesammelt hast, kannst du das Tag sogar als Index für den Array-Zugriff verwenden
Selbstverständlich muss ein und dieselbe "OnEditingDone"-Prozedur für alle 20 DBDateEdit's zugewiesen werden.
Zuletzt geändert von Zvoni am Mo 13. Jan 2025, 10:07, insgesamt 3-mal geändert.
Ein System sie alle zu knechten, ein Code sie alle zu finden,
Eine IDE sie ins Dunkel zu treiben, und an das Framework ewig zu binden,
Im Lande Redmond, wo die Windows drohn.

musicto
Beiträge: 5
Registriert: Do 11. Apr 2024, 07:32

Re: Variabler Zugriff auf Komponenten aus anderer unit

Beitrag von musicto »

Ok, ich glaube ich verstehe warum mein Code nicht funktioniert.
Eventuell hilft mir FindComponent weiter.

Edit:
Danke Zvoni, ebenfalls ein guter Ansatz!

Generell:
Ist das Auslagern von Code in eine andere Unit um die Lesbarkeit zu erhöhen prinzipiell keine gute Entscheidung? Oder birgt dies technische Nachteile?

Grüße

Sascha

Benutzeravatar
Zvoni
Beiträge: 408
Registriert: Fr 5. Jul 2024, 08:26
OS, Lazarus, FPC: Windoof 10 Pro (Laz 2.2.2 FPC 3.2.2)
CPU-Target: 32Bit
Wohnort: BW

Re: Variabler Zugriff auf Komponenten aus anderer unit

Beitrag von Zvoni »

musicto hat geschrieben: Mo 13. Jan 2025, 09:57 Ok, ich glaube ich verstehe warum mein Code nicht funktioniert.
Eventuell hilft mir FindComponent weiter.
Wozu? FindComponent bringt nur (mMn) unnötigen Overhead, und nagelt dich auf die Namen der Controls fest.
Mit meiner Variante (Array und Tags), sowie dynamischer Zuweisung des OnEditingDone-Events könnte man sogar die Namen der Controls ändern wie man will, ohne dann im Quellcode alles ersetzen zu müssen (wobei zugegebenermassen ich hier nicht ganz sicher bin)

Generell:
Ist das Auslagern von Code in eine andere Unit um die Lesbarkeit zu erhöhen prinzipiell keine gute Entscheidung? Oder birgt dies technische Nachteile?

Grüße

Sascha
Abseits der bereits festgestellten Probleme?
Code, der zusammengehört (und nicht anderweitig verwendet wird), gehört zusammen in eine Unit

EDIT: Anbei ein kleines Proof of Concept (Hab "normale" DateEdits verwendet).
Hinweis: Ich habe jetzt die "OnEditingDone"-Prozedur nur bei den "Startdatum"-Controls zugewiesen (Also kein Check auf "gerade/ungerade").
Ausserdem ist man bei dieser Variante auch auf die Control-Namen festgelegt (wobei das aber eigentlich nicht ein Problem sein sollte, falls man die Namen ändert, da man dann nur an einer Stelle anpassen muss)
DateEdit.zip
(2.08 KiB) 36-mal heruntergeladen
EDIT2: Hinweis: Ich hab im englischen Forum nen Vorschlag gemacht für eine neue EndOftheMonth/IsLeapYear-Funktion.
Damit könnte man sich die "Uses DateUtils" ggfs. sparen
Ein System sie alle zu knechten, ein Code sie alle zu finden,
Eine IDE sie ins Dunkel zu treiben, und an das Framework ewig zu binden,
Im Lande Redmond, wo die Windows drohn.

musicto
Beiträge: 5
Registriert: Do 11. Apr 2024, 07:32

Re: Variabler Zugriff auf Komponenten aus anderer unit

Beitrag von musicto »

Oh klasse,

vielen lieben Dank!

Das kann ich sehr gut verwenden!

Grüße

Sascha

Benutzeravatar
Zvoni
Beiträge: 408
Registriert: Fr 5. Jul 2024, 08:26
OS, Lazarus, FPC: Windoof 10 Pro (Laz 2.2.2 FPC 3.2.2)
CPU-Target: 32Bit
Wohnort: BW

Re: Variabler Zugriff auf Komponenten aus anderer unit

Beitrag von Zvoni »

musicto hat geschrieben: Mo 13. Jan 2025, 11:45 Oh klasse,

vielen lieben Dank!

Das kann ich sehr gut verwenden!

Grüße

Sascha
Kann mich nur wiederholen: Das absolut wichtige ist die korrekte "Reihenfolge" der Tag-Eigenschaften.
Das machst du einmal und gut ist.
Man könnte sogar die Zuweisung der DateEdits an das Array in FormCreate dynamisieren (und somit unabhängig vom Control-Namen machen), sofern keine weiteren DateEdits auf dieser Form sind (oder sofern doch noch weitere DateEdits auf der Form sind, diese einen Tag bekommen, welcher "ausserhalb" der Array-Range liegt).
Einfach über die Controls iterieren, auf "Is TDBDateEdit" prüfen (ggfs. in zweitem Schritt prüfen, ob Tag zwischen 0 und 19 liegt)

Aircode:

Code: Alles auswählen

Var t:TControl;
Begin
  For Each T in MyForm.Components Do
    If T Is TDBDateEdit Then MyArray[TDBDateEdit(t).Tag]:=TDBDateEdit(t);  //ggfs. Check ob Tag zwischen 0 und 19 liegt
 End;
Ein System sie alle zu knechten, ein Code sie alle zu finden,
Eine IDE sie ins Dunkel zu treiben, und an das Framework ewig zu binden,
Im Lande Redmond, wo die Windows drohn.

Antworten