![]() |
[XE5]: Nutzung des Datenmoduls
Hallo,
ich habe das Problem, das ich den Inhalt einer Variablen in mehreren Units nutzen will und diese Units nicht gegenseitig in die uses eintragen wiil. Also, dachte ich mir:"Nimm doch ein Datenmodul." Also, ein Datenmodul erstellt und die eine Variable vom Typ integer darin definiert. Wenn ich jetzt in Unit 1 der Variablen einen Wert zuweise, kann ich ihn auch in Unit 1 wieder auslesen. Aber, in keinen anderen Unit. Das Datenmodul ist in den uses der units eingetragen. Habe ich einen Denkfehler? Kann man ein Datenmodul so nicht nutzen? Ich habe das Problem auch schon in d.c.l.d.m. ![]() Vieleicht habe ich ja ein grundsätzlichen Gedankenfehler (in Bezug auf die Datenmodule :-D )den wir bisher übersehen haben. Gruß Heiko |
AW: [XE5]: Nutzung des Datenmoduls
Wozu soll das Datenmodul gut sein, wenn es garnicht benutzt und nichtmal irgendwo instanziiert wird?
Eine globale Variable kann man auch so deklarieren. Im Endeffekt läuft dein gezeigter Code darauf hinaus und dieser ist eigentlich korrekt, auch wenn nicht unbedingt schön.
Delphi-Quellcode:
unit meineschrottigenglobalenvariablen;
interface var MaxLine: integer; Symboltyp: Integer; implementation end. Wie und wo verwendest du diese Variablen? Antwort: Mit deinem Datenmodul ist alles in Ordnung, da es nichts macht. Aber da du sonst alles Wichtige über die Variablen verschweigst, kann dir Keiner helfen. |
AW: [XE5]: Nutzung des Datenmoduls
Hallo,
für solche Zwecke reicht eine Unit völlig aus. Du möchtest programmweit erreichbare (also globale) Variablen:
Delphi-Quellcode:
Ein Datenmodul ist ja eher ein nonvisuelles Form - ich pack da immer alle meine Datenbankobjekte rein.
unit globalsUnit;
interface var UserId : integer; UserRoleId : integer; UserName : string; implementation end. Viele Grüße …. |
AW: [XE5]: Nutzung des Datenmoduls
Als globalen Speicher immer ein Singleton (Klasse oder Interface) benutzen.
Warum:
Hört sich kompliziert an, ist es aber nicht.
Delphi-Quellcode:
über ein Interface
unit GlobalStore;
interface type Global = class private class var FUserID : Integer; class var FUserRoleID : Integer; class var FUsername : string; class procedure SetUserID( const Value : Integer ); class procedure SetUsername( const Value : string ); static; class procedure SetUserRoleID( const Value : Integer ); static; public class property UserID : Integer read FUserID write SetUserID; class property UserRoleID : Integer read FUserRoleID write SetUserRoleID; class property Username : string read FUsername write SetUsername; end; implementation { Global } procedure Global.SetUserID( const Value : Integer ); begin FUserID := Value; end; class procedure Global.SetUsername( const Value : string ); begin FUsername := Value; end; class procedure Global.SetUserRoleID( const Value : Integer ); begin FUserRoleID := Value; end; end.
Delphi-Quellcode:
unit GlobalStore;
interface type IGlobal = interface ['{F0A0B4C5-44CF-401A-983E-B68CF010A0AD}'] function GetUserID : Integer; procedure SetUserID( const Value : Integer ); property UserID : Integer read GetUserID write SetUserID; function GetUserRoleID : Integer; procedure SetUserRoleID( const Value : Integer ); property UserRoleID : Integer read GetUserRoleID write SetUserRoleID; function GetUsername : string; procedure SetUsername( const Value : string ); property Username : string read GetUsername write SetUsername; end; function Global : IGlobal; implementation type TGlobal = class( TInterfacedObject, IGlobal ) private class var _Default : IGlobal; private FUserID : Integer; FUserRoleID : Integer; FUsername : string; public class function Default : IGlobal; function GetUserID : Integer; function GetUserRoleID : Integer; function GetUsername : string; procedure SetUserID( const Value : Integer ); procedure SetUserRoleID( const Value : Integer ); procedure SetUsername( const Value : string ); end; function Global : IGlobal; begin Result := TGlobal.Default; end; { TGlobal } class function TGlobal.Default : IGlobal; begin if not Assigned( _Default ) then _Default := TGlobal.Create; Result := _Default; end; function TGlobal.GetUserID : Integer; begin Result := FUserID; end; function TGlobal.GetUsername : string; begin Result := FUsername; end; function TGlobal.GetUserRoleID : Integer; begin Result := FUserRoleID; end; procedure TGlobal.SetUserID( const Value : Integer ); begin FUserID := Value; end; procedure TGlobal.SetUsername( const Value : string ); begin FUsername := Value; end; procedure TGlobal.SetUserRoleID( const Value : Integer ); begin FUserRoleID := Value; end; end. |
AW: [XE5]: Nutzung des Datenmoduls
Moin,
Zitat:
Zitat:
Zitat:
Delphi-Quellcode:
und hier zum Beispiel genutzt:
unit allgemein;
interface uses .... datenmodul; // Einbinden um Felder deaktivieren zu können private { Private-Deklarationen } public { Public-Deklarationen } end; var Form_Allgemein: TForm_Allgemein; implementation {$R *.dfm} procedure TForm_Allgemein.CoB_SymboltypChange(Sender: TObject); begin datenmodul.MaxLine:= CoB_Symboltyp.ItemIndex; CB_Activate_Symbol.Caption:=IntToStr(CoB_Symboltyp.ItemIndex)+'##'+inttostr(datenmodul.MaxLine); end; end.
Delphi-Quellcode:
unit anschluesse;
interface uses ..., datenmodul; // Einbinden um Felder deaktivieren zu können private { Private-Deklarationen } public { Public-Deklarationen } end; var Form_Anschluesse: TForm_Anschluesse; implementation {$R *.dfm} procedure TForm_Anschluesse.FormShow(Sender: TObject); begin lbledt_AnzAnschluesse.EditLabel.Caption:=IntToStr(datenmodul.MaxLine); if datenmodul.MaxLine in [7,8,9,10,11,12,13,14] then begin Form_Anschluesse.chklst_GAnschluesse.Enabled:=False; Form_Anschluesse.chklst_KAnschluesse.Enabled:= False; Form_Anschluesse.lbledt_AnzAnschluesse.Enabled:=False; end else if datenmodul.MaxLine = 6 then begin Form_Anschluesse.chklst_GAnschluesse.Enabled:=False; Form_Anschluesse.chklst_KAnschluesse.Enabled:= True; Form_Anschluesse.lbledt_AnzAnschluesse.Enabled:=True; end else begin Form_Anschluesse.chklst_GAnschluesse.Enabled:=True; Form_Anschluesse.chklst_KAnschluesse.Enabled:=false; Form_Anschluesse.lbledt_AnzAnschluesse.Enabled:=False; end; end; Zitat:
Zitat:
Gruß Heiko |
AW: [XE5]: Nutzung des Datenmoduls
Moin,
Zitat:
Und da ich noch nicht weiß, was in der nächsten Ausbaustufe alles kommt, wollte ich halt jetzt schon alle "globalen" Datenspeicher an einem Ort zusammenfassen. Gruß Heiko |
AW: [XE5]: Nutzung des Datenmoduls
Moin,
Zitat:
Und packst Du das in eine "normale" Unit oder in ein Datenmodul? Und wie greifst Du aus einer anderen Unit darauf zu? Gruß HEiko |
AW: [XE5]: Nutzung des Datenmoduls
Bei der
Delphi-Quellcode:
Variante heißt die Klasse
class
Delphi-Quellcode:
und bei der
Global = class
Delphi-Quellcode:
Variante gibt es eine
interface
Delphi-Quellcode:
.
function Global : IGlobal;
Beide Varianten sind in der Benutzung identisch
Delphi-Quellcode:
unit Somewhere;
interface procedure foo; implementation uses GlobalStore; procedure foo; begin if Global.UserID = 10 then ... end; |
AW: [XE5]: Nutzung des Datenmoduls
Auch zu einem Datenmodul gehört eine Unit, das hat mit globalen Variablen nur sehr wenig zu tun.
![]() Zitat:
|
AW: [XE5]: Nutzung des Datenmoduls
Sir Rufo hat dir schon eine vollständige Lösung für dein Problem gezeigt.
Um sein letztes Beispiel nochmal zu verdeutlichen:
Delphi-Quellcode:
unit SomeOtherUnitFromYourProject;
interface procedure BlaBla; implementation uses GlobalStore; //ja, das ist die gleiche Unit procedure BlaBla; begin GlobalStore.Global.UserID := 10; if GlobalStore.Global.UserName = 'Kralle' then begin Writeln('Brauche eigentlich für mein Problem kein Datenmodul!'); end; end; |
AW: [XE5]: Nutzung des Datenmoduls
Und wenn man den GlobalStore mit ein wenig Logik versieht, dann wird beim Setzen von
Delphi-Quellcode:
auch schon passend dazu
Global.UserId
Delphi-Quellcode:
und
Global.UserRoleID
Delphi-Quellcode:
gesetzt.
Global.Username
Oder das passiert auch beim Setzen des Usernamen (UserID, UserRoleID). UserRoleID könnte zudem auch ReadOnly sein :) Oder alle Felder sind ReadOnly und es gibt noch eine Login-Methode die dann diese Felder setzt. Oder ... |
AW: [XE5]: Nutzung des Datenmoduls
Folgende zwei Codefragmente sind äquivalent:
Delphi-Quellcode:
Das ist im Prinzip nix anderes wie 3 globale Variablen
type
Global = class private class var FUserID : Integer; class var FUserRoleID : Integer; class var FUsername : string; class procedure SetUserID( const Value : Integer ); class procedure SetUsername( const Value : string ); static; class procedure SetUserRoleID( const Value : Integer ); static; public class property UserID : Integer read FUserID write SetUserID; class property UserRoleID : Integer read FUserRoleID write SetUserRoleID; class property Username : string read FUsername write SetUsername; end;
Delphi-Quellcode:
Ob man jetzt noch ein Interface darüberlegt oder den Username automatisch mit der UserID setzt ändert nichts daran dass hier ein "Sack voller globaler Variablen" vorliegt.
var
UserID : Integer; UserRoleID : Integer; Username : string; Ich habe dazu ein ![]() |
AW: [XE5]: Nutzung des Datenmoduls
Der Vorteil es nicht nur als viele globale Variablen zu machen, ist der, daß man sich später problemlos da überall reinhängen kann, ohne daß am Aufrufenden Code etwas geändert werden muß.
Das reicht schon vollkommen.
Delphi-Quellcode:
Getter und Setter läßt sich nachträglich einfügen und schon kann man Code für eine Werte-Kontrolle der Felder integrieren, oder ein Logging oder oder oder...
type
Global = class abstract private class var FUserID : Integer; FUserRoleID : Integer; FUsername : string; public class property UserID : Integer read FUserID write FUserID; class property UserRoleID : Integer read FUserRoleID write FUserRoleID; class property Username : string read FUsername write FUsername; end; Und viel mehr Aufwand ist es auch nicht.
Delphi-Quellcode:
Nun nur noch Strg+Alt+C (Klassenvervollständigung) und fertig isses.
type
Global = class abstract class property UserID : Integer; class property UserRoleID : Integer; class property Username : string; end; OK, abgesehn von dem BUG, welcher hier grade auftritt. Denn so sollte das Ergebnis der Klassenvervollständigung wirklich nicht aussehn.
Delphi-Quellcode:
Global = class abstract
class property UserID : Integer read FUserID write SetUserID; class property UserRoleID : Integer read FUserRoleID write SetUserRoleID; class property Username : string read FUsername write SetUsername; private FUserID: Integer; private class var FUserRoleID: Integer; private class var FUsername: string; private private private procedure SetUserID(const Value: Integer); class procedure SetUsername(const Value: string); static; class procedure SetUserRoleID(const Value: Integer); static; end; |
AW: [XE5]: Nutzung des Datenmoduls
Zitat:
In einer Klasse/Interface werden die aber kontrollierbar. |
AW: [XE5]: Nutzung des Datenmoduls
Wieso kann man eigentlich keine Class Const deklarieren, und auch kein Class Type? Ich hab diese geniale Idee mit den Klassenvariablen nämlich gleich mal ausprobiert, um nicht immer alles im Datenmodul deklarieren zu müssen.
|
AW: [XE5]: Nutzung des Datenmoduls
Zitat:
Die Konstanten sind immer da und erreichbar und die Types auch |
AW: [XE5]: Nutzung des Datenmoduls
Hab Dank, Sir Rufo, genau das hatte ich vermutet, denn es hat bei Const und Type auch ohne vorangestelltes Class funktioniert :thumb:
|
AW: [XE5]: Nutzung des Datenmoduls
Es gibt
Delphi-Quellcode:
, wo der Compiler und auch zur Laufzeit eine Exception werfen sollte, wenn man versucht davon eine Instanz zu createn. (die weitere Vererbung könnte man auch noch abschalten)
class abstract
Und du kannst es auch gerne als Record deklarieren. In die Klasse rein, kann man auch noch abhängige/private Typen und Konstanten aufnehmen, welche dann nicht im Kontext der Unit "öffentlich" rumschwirren. |
AW: [XE5]: Nutzung des Datenmoduls
Hallo,
erstmal Entschuldigung das ich erst jetzt antworte. Ich habe gerade versucht das jetzt umzusetzen - leider ohne Erfolg. Ich habe eine neue Unit angelegt und so gefüllt:
Delphi-Quellcode:
Wenn das Projekt erstellen will bekomme ich diese Fehlermeldungen:
unit datenmodul;
interface type Global = class private class var FSymboltyp : Integer; class procedure SetSymboltyp (const Value : Integer); public class property Symboltyp : Integer read FSymboltyp write SetSymboltyp; end; implementation procedure Global.SetSymboltyp(const Value : Integer); begin FSymboltyp:=Value; end; end. Zitat:
Wenn es sich um eine Tippfehler handelt, finde ich ihn nicht. Könnt Ihr noch mal schauen? Gruß Heiko |
AW: [XE5]: Nutzung des Datenmoduls
Delphi-Quellcode:
Es ist ja als Klassenmethode deklariert, deshalb muss es auch so implementiert werden.
class procedure Global.SetSymboltyp(const Value : Integer);
begin FSymboltyp:=Value; end; |
AW: [XE5]: Nutzung des Datenmoduls
Hallo Detlef,
Zitat:
Zitat:
|
AW: [XE5]: Nutzung des Datenmoduls
Zitat:
Delphi-Quellcode:
?
class var
|
AW: [XE5]: Nutzung des Datenmoduls
Es steht ja da: die Setter-Methode muss statisch sein.
Delphi-Quellcode:
Allerdings würde ich persönlich bei der üblichen Nomenklatur bleiben und dem Klassennamen noch ein "T" voranstellen.
Global = class
private class var FSymboltyp : Integer; class procedure SetSymboltyp (const Value : Integer); static; //hier public class property Symboltyp : Integer read FSymboltyp write SetSymboltyp; end; |
AW: [XE5]: Nutzung des Datenmoduls
Zitat:
Von daher würde ich dieser Klasse eben kein T voranstellen :) |
AW: [XE5]: Nutzung des Datenmoduls
Dann sag mal bei Emba Bescheid, dass sie z.B. TEncoding falsch benannt haben.
|
AW: [XE5]: Nutzung des Datenmoduls
Zitat:
Oder welchen Typ hat die Instanz
Delphi-Quellcode:
?
UTF8
Hier kann man es sehen ![]() |
AW: [XE5]: Nutzung des Datenmoduls
![]() Zitat:
|
AW: [XE5]: Nutzung des Datenmoduls
Moin,
es gibt jetzt zwar beim Compilieren keine Fehlermeldung mehr, aber der Variableninhalt wird nicht übertragen. Setzen:
Delphi-Quellcode:
Auslesen:
unit allgemein;
... implementation {$R *.dfm} uses datenablage; procedure TForm_Allgemein.CoB_SymboltypChange(Sender: TObject); begin Global.Symboltyp:= CoB_Symboltyp.ItemIndex; CB_Activate_Symbol.Caption:=IntToStr(CoB_Symboltyp.ItemIndex)+'##'+inttostr(datenablage.Global.Symboltyp); end;
Delphi-Quellcode:
Hier kommt nichts an.
unit anschluesse;
... implementation {$R *.dfm} uses datenablage; procedure TForm_Anschluesse.FormShow(Sender: TObject); begin lbledt_AnzAnschluesse.EditLabel.Caption:=IntToStr(Global.Symboltyp); if Global.Symboltyp in [7,8,9,10,11,12,13,14] then Warum? Gruss Heiko |
AW: [XE5]: Nutzung des Datenmoduls
Das können wir dir nicht sagen, weil wir nicht wissen, in welcher Reihenfolge das aufgerufen wird.
Wenn die Form Anschlüsse schon angezeigt wird und du dann erst die Änderung machst, dann "kommt" der Wert da nicht an, weil der Wert ja nicht durch Magie die Methode aufruft. |
AW: [XE5]: Nutzung des Datenmoduls
Wo landest Du, wenn Du in beiden Units einmal mit STRG-Linksklick auf "Global" abspringst? Ist das auch dieselbe Stelle?
|
AW: [XE5]: Nutzung des Datenmoduls
Hallo Rufo;
Zitat:
Delphi-Quellcode:
Beim laufenden Programm wähle ich erst auf dem TAB "Allgemein" den Symboltyp aus und Wechsel dann auf den TAB "Anschluesse".
procedure TMainForm.FormCreate(Sender: TObject);
begin // Die Einzelnen Units an die TABs binden Form_Allgemein:= TForm_Allgemein.Create(Self); Form_Allgemein.Parent:=Tab01_Allgemein; Form_Allgemein.Show; // // Form_Anschluesse:= TForm_Anschluesse.Create(Self); Form_Anschluesse.Parent:=Tab05_Anschluesse; Form_Anschluesse.Show; end; Was mir gerade noch auffiel: Ich habe kein "Blauen Punkte" vor den Codezeilen und Breakpoints nutzen auch nichts. Unter XE2 hat damals das geholfen: Zitat:
Gruß Heiko |
AW: [XE5]: Nutzung des Datenmoduls
Moin,
Zitat:
Delphi-Quellcode:
Gruß HEiko
unit datenablage;
interface type Global = class |
AW: [XE5]: Nutzung des Datenmoduls
Aber dann ist es doch logisch, dass du die Änderung nicht in der Form siehst.
Du holst die Werte beim OnShow Event ab und der ist doch schon lange durch :roll: |
AW: [XE5]: Nutzung des Datenmoduls
Hallo Rufo,
Zitat:
![]() Da stand ich mir mal wieder selber im Weg. Welches Ereignis wird denn ausgeführt, wenn ich von einem TAB auf den anderen Wechsel? Okay, ich muß mein Konzept wohl überdenken, das ich alles in den jeweiligen Units lösen will und eine Teil in das "OnChange" des "PageControls" verlegen. Oder ich definiere eine "Globale"-Variable im "OnChange" die mir anzeigt, das ein TAB gewechselt wurde. Gruß Heiko |
Alle Zeitangaben in WEZ +1. Es ist jetzt 12:18 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz