Mehrere Units zu einer zusammenfassen

Für Fragen von Einsteigern und Programmieranfängern...
Antworten
Carsten1975
Beiträge: 23
Registriert: Mi 4. Apr 2018, 18:22

Mehrere Units zu einer zusammenfassen

Beitrag von Carsten1975 »

Hallo zusammen,

ich habe mehrere Units mit diversen Prozeduren und Funktionen, gleichzeitig sind aber auch Records und Variablen enthalten.

Code: Alles auswählen

Unit AllUnits;

  {$mode objfpc}{$H+}

  Interface

    Uses
      Classes,
      UTest1,   // TgTest1
      UTest2,   // TgTest2
      UTest3;   // TgTest3
     
    Type

      TgAllUnits = Class
        gU1   : TgTest1;
        gU2   : TgTest2;
        gU3   : TgTest3;
Hauptunit

Code: Alles auswählen

pAU : TgAllUnits;
Wie bekomme ich es jetzt hin, dass ich auf die einzelnen Prozeduren und Funktionen, sowie Records und Variablen zugreifen kann?

pAU.gU1.Init();
oder
pAU.gU2.gvTest := 2;


Mit dem Thema Wrapper Unit funktioniert es irgendwie nicht.

Vielen Dank für eure Antworten

Socke
Lazarusforum e. V.
Beiträge: 3158
Registriert: Di 22. Jul 2008, 19:27
OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 10/Linux/Raspbian/openSUSE
CPU-Target: 32bit x86 armhf
Wohnort: Köln
Kontaktdaten:

Re: Mehrere Units zu einer zusammenfassen

Beitrag von Socke »

Und was willst du damit erreichen? Normalerweise nennst du in einer Unit alle anderen Units, die du dort verwenden willst. Das reicht aus um auf alles darin zugreifen zu können.
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein

Carsten1975
Beiträge: 23
Registriert: Mi 4. Apr 2018, 18:22

Re: Mehrere Units zu einer zusammenfassen

Beitrag von Carsten1975 »

Ich habe an die 150 Funktionen und Prozeduren.

Diese sind nach Themengebieten sortiert.

In einer Unit habe ich spezielle Funktionen und Prozeduren zur Bearbeitung von String-Zeichenketten.
In einer anderen Unit habe ich spezielle Funktionen und Prozeduren zur Bearbeitung von Integer-Zeichenketten und Berechnungen.

Dann habe ich Units wo ich Funktionen und Prozeduren zur dynamischen Erstellung von Feldern habe und in einer anderen wiederum von DB-Feldern.

Diese Units möchte ich zu Themengebieten (Packages) zusammenfassen.

Pkg Zeichenketten
-> Unit pUZeichenketten
enthält:
-> Unit UInteger
-> Unit UStrings

Pkg Fields
-> Unit pUFields
enthält:
-> Unit UEingabefelder
-> Unit UDB-Felder

Da ich aber nicht immer alle Units einzeln einbinden möchte, möchte ich einfach die Unit pUZeichenketten einbinden und auf alle Units zugreifen können die in diesem Package enthalten sind und nicht jedesmal die Unit UInteger und Unit UStrings einbinden.

Und ich denke, dass viele Programmierer sich mit der Zeit solche Themenpackages anlegen sollten um vernünftig und strukturiert programmieren zu können.


@Socke: Und zum Schluss hast du keinen Überblick mehr aus welcher Unit du welche Funktion oder Prozedur verwendet hast, wenn du nach Fehlern suchst. Na klar kannst du den Debugger verwenden, aber machmal ist es auch mit dem sehr mühsam, weil man einfach sehr viel Zeit aufwenden muss.
Und ich spreche hier von Projekten mit insgesamt mehr als 1 Mio Zeilen Quelltext.

Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 6209
Registriert: So 7. Jan 2007, 10:20
OS, Lazarus, FPC: FPC fixes Lazarus fixes per fpcupdeluxe (win,linux,raspi)
CPU-Target: 32Bit (64Bit)
Wohnort: Burgenland
Kontaktdaten:

Re: Mehrere Units zu einer zusammenfassen

Beitrag von af0815 »

Ich fasse solche Themen in Komponenten zusammen. Wenn ich was aus einem Paket benötige, so binde die Komponente ein und im Projekt dann die Unit aus der Komponente. Damit verliert man nie den Überblick. Wenn ich was suche so springe ich mit dem Editor einfach in die Deklaration von der Prozedur/Funktion und gut ist es.
Noch dazu kann man diese Komponenten testen und dann braucht man sich keine Gedanken bezüglich Fehlersuche machen. Funktioniert genauso, wie die LCL.
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

Socke
Lazarusforum e. V.
Beiträge: 3158
Registriert: Di 22. Jul 2008, 19:27
OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 10/Linux/Raspbian/openSUSE
CPU-Target: 32bit x86 armhf
Wohnort: Köln
Kontaktdaten:

Re: Mehrere Units zu einer zusammenfassen

Beitrag von Socke »

Carsten1975 hat geschrieben:
So 2. Jan 2022, 13:55
@Socke: Und zum Schluss hast du keinen Überblick mehr aus welcher Unit du welche Funktion oder Prozedur verwendet hast, wenn du nach Fehlern suchst. Na klar kannst du den Debugger verwenden, aber machmal ist es auch mit dem sehr mühsam, weil man einfach sehr viel Zeit aufwenden muss.
Dieses Problem löst sich ja nicht auf der Art und Weise, wie die Prozeduren in dein Projekt eingebunden werden. Die Suche, was wo definiert ist, bleibt dir nicht erspart. Hier kann dir wie du bereits angemerkt hast der Debugger oder auch die IDE helfen (z.B. Strg+Klick auf den Prozedurnamen usw.)

Bei deinem Problem sehe ich mehre Lösungswege - teilweise nicht sehr elegant. Ob oder wie gut diese durch den Compiler oder Lazarus unterstützt werden, habe ich nicht ausprobiert.
  • Du erstellt seine Include-Datei mit allen Unit-Namen. Diese referenzierst du per Compiler-Schalter in der Uses-Klausel. Das erscheint mir eine recht einfache Lösung ohne viel Overhead zu sein.
  • Du machst aus allen Units zwei Include-Files. Je eine für den Interface- un einen für den Implementation-Teil. Damit hast du weiterhin die Prozeduren thematisch getrennt, aber auf der anderen Seite doppelt so viele Dateien, die es zu verwalten und zu bearbeiten gilt.
  • Du baust wie in deinem ersten Post eine Wrapper-Unit. In dieser Wrapper-Unit deklarierst du alle Klassen und Prozeduren erneut. Das ist natürlich viel Schreibarbeit und vereinfacht nicht unbedingt das Debuggen. Hier kommte es ein wenig darauf an, wie du die Wrapper jeweils genau erstellst. Bei Prozeduren/Funktionen geht das ggf. so

    Code: Alles auswählen

     // Implementation-Teil
    function MySecretFunction: Integer; [Alias: 'MySecretFunction'];
    begin
      Result := 42;
    end;
    // Wrapper-Unit kann jetzt direkt darauf referenzieren:
    function MySecretFunction: Integer; external name 'MySecretFunction';
    
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein

Carsten1975
Beiträge: 23
Registriert: Mi 4. Apr 2018, 18:22

Re: Mehrere Units zu einer zusammenfassen

Beitrag von Carsten1975 »

Danke für die ausführliche Antwort.

Ich habe mich für die letzte Variante entschieden.

pWrapper:

Code: Alles auswählen

Unit pWrapper;

  {$mode objfpc}{$H+}

  Interface

    Uses
      Classes,
      SysUtils,
      UTest1,
      UTest2,
      UTest3;

    Type

      { TgWrapper }

      TgWrapper  = Class
        gUTest1   : TgTest1;
        gUTest2   : TgTest2;
        gUTest3   : TgTest3;
 
        Private

        Public
          { Öffentliche Objekte können überall da gesehen werden, wo die Klasse verwendet wird }

          Constructor Create;
          Destructor Destroy; Override;

      End;

      // UTest1

      Procedure gUTest1_gpInit; external name 'gpInitialisierung';

      Function gUTest1_gpSQL(ugrSQLQuery : grTSQLQuery;
                           uStart_int  : Integer = -1;
                           uEnde_int   : Integer = -1) : grTSQLQuery; external name 'gpSQL';

      // UTest2

      Procedure gUTest2_gpInit; external name 'gpInitialisierung';


      // UTest3

      Procedure gUTest3_gpLiz(uStatus_str : String); external name 'gpLizenz';


    Var

      pUWrapper : TgWrapper;


       // UTest3

      gUTest3_grLizenz  : grTLizenz; external name 'grLizenz';
      gUTest3_grLizenzM : grTLizenzModul; external name 'grLizenzModul';


 Implementation

    Constructor TgWrapper.Create;
    Begin
      Inherited Create;
    End;

    Destructor TgWrapper.Destroy;
    Begin
      Inherited Destroy;
    End;

End.
UTest1

Code: Alles auswählen

Procedure gpInitialisierung(); [Alias: 'gUTest1_gpInit'];

Function gpSQL(ugrSQLQuery : grTSQLQuery;
                       uStart_int  : Integer = -1;
                       uEnde_int   : Integer = -1) : grTSQLQuery; [Alias: 'gUTest1_gpSQL'];

UTest2

Code: Alles auswählen

Procedure gpInitialisierung(); [Alias: 'gUTest2_gpInit'];
UTest3

Code: Alles auswählen

Procedure gpLizenz(uStatus_str : String); [Alias: 'gUTest3_gpLiz'];

grLizenz      : grTLizenz;
grLizenzModul : grTLizenzModul;

Wenn ich die pWrapper jetzt in mein Formular in den Uses einbinde und dort wie folgt aufrufe:

FrmMain

Code: Alles auswählen

Uses
   pWrapper;


Implementation

Begin

pUWrapper.Create;

pWrapper.gUTest1_gpInit;             <----- pUWrapper  funktioniert hier nicht

pWrapper.gUTest3_grLizenz[0].vName_str := 'Test';             <----- pUWrapper  funktioniert hier nicht

End;
,


dann bekomme ich die Fehlermeldungen:

Error: Undefined Symbol: gpInitialisierung
Error: Undefined Symbol: gpLizenz
Error: Undefined Symbol: grLizenz
Error: Undefined Symbol: gpSQL


Was mache ich jetzt noch falsch?

Muss ich noch etwas registrieren?

Socke
Lazarusforum e. V.
Beiträge: 3158
Registriert: Di 22. Jul 2008, 19:27
OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 10/Linux/Raspbian/openSUSE
CPU-Target: 32bit x86 armhf
Wohnort: Köln
Kontaktdaten:

Re: Mehrere Units zu einer zusammenfassen

Beitrag von Socke »

Ich möchte noch auf eine ganz andere Vorgehensweise hinweisen: du könntest eine Projektvorlage anlegen und dort deine Standard-Units bereits hinterlegen. Vielleicht willst du das Package auch erweitern, sodass auch einzelne Unit-Vorlagen möglich sind?
Carsten1975 hat geschrieben:
So 2. Jan 2022, 18:18
Was mache ich jetzt noch falsch?
Du musst exakt auf die Schreibweisen achten. Bei mir knallt es schon bereits daran, dass TgTest1 bis TgTest3 nicht gefunden werden. Die sind in keiner deiner Qulltextbeispiele enhalten. Ebenso schreibst du Procedure gUTest2_gpInit; external name 'gpInitialisierung'; in pWrapper, in der Unit2 heißt es dann aber Procedure gpInitialisierung(); [Alias: 'gUTest2_gpInit'];.

Dieses Vorgehen bringt dir vermutlich neben sehr viel Arbeit auch etliche neue Fehler.
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein

charlytango
Beiträge: 843
Registriert: Sa 12. Sep 2015, 12:10
OS, Lazarus, FPC: Laz stable (2.2.6, 3.x)
CPU-Target: Win 32/64, Linux64
Wohnort: Wien

Re: Mehrere Units zu einer zusammenfassen

Beitrag von charlytango »

Als recht simpler Geist verstehe ich irgendwie nicht den Sinn hinter der ganzen Aktion.

Wenn ich das richtig verstanden habe wolltest du Schreibarbeit einsparen und nur eine einzige Unit einbinden um mehrere Units zusammenzufassen.

Mit dem Ergebnis dass nach mehrmaligem Umbenennen (wo ich nicht weiß was der Debugger damit anstellt und sicher auch die Sprungpositionen erhöht) an jeder Position an der eine Funktion/Prozedur aus dem Konglomerat gebraucht wird voll qualifizierte Schreibweise nötig wird? Das ist dann eine Einsparung?

Da bleibe ich lieber bei meinem tradierten Konzept und binde nur die Units ein die ich wirklich benötige. Der Editor findet ohnedies zuverlässig die Deklaration der verwendeten Funktion/Prozedur. Shortkeys sind da recht hilfreich (oder auch Ctrl-Mausklick)
Bestenfalls mit dem Komponentenansatz von @af0815 könnte ich mich noch anfreunden.

Carsten1975
Beiträge: 23
Registriert: Mi 4. Apr 2018, 18:22

Re: Mehrere Units zu einer zusammenfassen

Beitrag von Carsten1975 »

Also warum ich das so machen möchte spielt im Moment einfach keine Rolle.

@Socke: Was die TgTest1 bis TgTest3 angeht, so sind das die Klassen aus den Units UTest1 bis UTest3. Die habe ich jetzt natürlich hier nicht gepostet, sondern nur die globalen Prozeduren (beginnen mit gp) aus den einzelnen Klassen. Die Klassen benötige ich um dort auf die Variablen zugreifen zu können.

Mir geht es jetzt einfach darum, warum die Fehlermeldungen kommen?

Oder wie würdest du einen Wrapper schreiben, in dem auch Variablen aus den Units enthalten sein sollen?

hum4n0id3
Beiträge: 301
Registriert: So 5. Mai 2019, 15:23

Re: Mehrere Units zu einer zusammenfassen

Beitrag von hum4n0id3 »

Carsten1975 hat geschrieben:
So 2. Jan 2022, 23:59
Also warum ich das so machen möchte spielt im Moment einfach keine Rolle.
Sollte es aber. Denn wenn dein Code schon am Anfang schlecht ist, wird es im Verlauf einer weiteren Entwicklung gar nicht besser. Das kann zudem dazu führen dass das Projekt letztendlich auch vorzeitig beendet werden kann. Weil nichts mehr geht. Außerdem wie ich die Sache sehe, fehlt dir noch Grundlagen-Wissen run um Pascal und Klassen. Oder auch bei mir, da ich nicht viel mit Pascal mache.

Code: Alles auswählen

pUWrapper.Create;

pWrapper.gUTest1_gpInit;             <----- pUWrapper  funktioniert hier nicht

pWrapper.gUTest3_grLizenz[0].vName_str := 'Test';             <----- pUWrapper  funktioniert hier nicht
Kann aus meiner Sicht gar nicht funktionieren. Oder habe ich was übersehen?

Benutzeravatar
Jorg3000
Lazarusforum e. V.
Beiträge: 169
Registriert: So 10. Okt 2021, 10:24
OS, Lazarus, FPC: Win64
Wohnort: NRW

Re: Mehrere Units zu einer zusammenfassen

Beitrag von Jorg3000 »

Die erste Zeile müsste lauten:

Code: Alles auswählen

pUWrapper:=TgWrapper.Create;

Carsten1975
Beiträge: 23
Registriert: Mi 4. Apr 2018, 18:22

Re: Mehrere Units zu einer zusammenfassen

Beitrag von Carsten1975 »

Also für alle die es interessiert, mit den Funktionen und Prozeduren klappt es bereits, nur noch nicht mit den Variablen.
Entscheidend hierbei ist, dass man die Compilerfunktion {$M+} mit einbindet und zwar in alle Units die betroffen sind (Hauptformular, Wrapper und die Units selber).

Zu beachten ist, dass ich somit Funktionen und Prozeduren, deren Units vielleicht den gleichen Aufbau mit den Namen haben, dementsprechend umbenennen kann.

Test1
- gpInitialisierung -> gUTest1_gpInit;

Test2
- gpInitialisierung -> gUTest2_gpInit;



Unit FFrmMain:

Code: Alles auswählen

Unit FFrmMain;

  {$mode objfpc}
  {$H+}
  {$M+}

  Interface

    Uses
      Classes,
      Controls,
      Forms,
      Graphics,
      StdCtrls,
      SysUtils,
      pWrapper;

    Type

      { TFFrmDat }

      TFFrmDat = Class(TForm)

        Procedure FormCreate(Sender : TObject);
        Procedure FormClose(Sender          : TObject;
                            Var CloseAction : TCloseAction);

      Private

      Public

    End;

    Var

      FFrmDat : TFFrmDat;



  Implementation

    {$R *.lfm}

    { TFrmKasseDat }

    Var

      pUWrapper := TgWrapper.Create;      //<-- Wird ausschließlich noch für die Variablen benötigt

    Procedure TFrmKasseDat.FormCreate(Sender : TObject);

    Begin
      pWrapper.gUTest1_gpInit; // Initialisierung UTest1
      pUWrapper.gUTest1.grLizenz := 0;      //<-- Variableninitialisierung
    End;
End.

Unit pWrapper:

Code: Alles auswählen

Unit pWrapper;

  {$mode objfpc}
  {$H+}
  {$M+}

  Interface

    Uses
      Classes,
      SysUtils,
      UTest1,
      UTest2,
      UTest3;

    Type

      { TgWrapper }

      TgWrapper = Class(TObject)
        Private

        Public
          { Öffentliche Objekte können überall da gesehen werden, wo die Klasse verwendet wird }

          gUTest1 : TgTest1;      //<-- Wird ausschließlich noch für die Variablen benötigt
          gUTest2 : TgTest2;      //<-- Wird ausschließlich noch für die Variablen benötigt
          gUTest3 : TgTest3;      //<-- Wird ausschließlich noch für die Variablen benötigt

 //         gUTest1_grLiz : grTLizenz; external name 'grLizenz';

          Constructor Create;
          Destructor Destroy; Override;

      End;
 
    // UTest1

    Procedure gUTest1_gpInit; external name 'gUTest1_gpInit';

    Function gUTest1_gpSQL(ugrSQLQuery : grTSQLQuery;
                         uStart_int  : Integer = -1;
                         uEnde_int   : Integer = -1) : grTSQLQuery; external name 'gUTest1_gpSQL';

    // UTest2

    Procedure gUTest2_gpInit; external name 'gUTest2_gpInit';


    // UTest3

    Procedure gUTest3_gpLiz(uStatus_str : String); external name 'gUTest3_gpLiz';


    Var

      pUWrapper : TgWrapper;

//      gUTest1_grLiz : grTLizenz; // external name 'grLizenz';


Implementation

    Constructor TgWrapper.Create;
    Begin
      Inherited Create;
    End;

    Destructor TgWrapper.Destroy;
    Begin
      Inherited Destroy;
    End;

End.

Unit UTest1:

Code: Alles auswählen

Unit UTest1;

  {$mode objfpc}
  {$H+}
  {$M+}

  Interface

    Uses
      Classes;

    Type

      TLizenzRecord = Record
        vName_str  : AnsiString;
      End;

      grTLizenz = Array of TLizenzRecord;

    Type

      { TgTest1 }

      TgTest1 = Class(TObject)

        Private

        Public
          grLizenz : grTLizenz;

          Procedure gpInitialisierung(); [Alias: 'gUTest1_gpInit'];

          Function gpSQL(ugrSQLQuery : grTSQLQuery;
                       uStart_int  : Integer = -1;
                       uEnde_int   : Integer = -1) : grTSQLQuery; [Alias: 'gUTest1_gpSQL'];

      End;




  Implementation

 ……

hum4n0id3
Beiträge: 301
Registriert: So 5. Mai 2019, 15:23

Re: Mehrere Units zu einer zusammenfassen

Beitrag von hum4n0id3 »

Jorg3000 hat geschrieben:
Di 4. Jan 2022, 03:54
Die erste Zeile müsste lauten:

Code: Alles auswählen

pUWrapper:=TgWrapper.Create;
Genau so verstehe ich das.

Carsten1975
Beiträge: 23
Registriert: Mi 4. Apr 2018, 18:22

Re: Mehrere Units zu einer zusammenfassen

Beitrag von Carsten1975 »

Es geht darum, dass hier 2 verschiedene Aufrufe stattfinden.

Code: Alles auswählen

    Begin
      pWrapper.gUTest1_gpInit; // Initialisierung UTest1
      pUWrapper.gUTest1.grLizenz := 0;      //<-- Variableninitialisierung
    End;
Nämlich einmal die Prozedure/Funktion mit pWrapper und
die Variable mit pUWrapper.

Und meine Frage ist ob es geht dies in einen Aufruf zu bekommen nämlich so:

Code: Alles auswählen

    Begin
      pWrapper.gUTest1_gpInit; // Initialisierung UTest1
      pWrapper.gUTest1.grLizenz := 0;      //<-- Variableninitialisierung
    End;
oder so?

Code: Alles auswählen

    Begin
      pUWrapper.gUTest1_gpInit; // Initialisierung UTest1
      pUWrapper.gUTest1.grLizenz := 0;      //<-- Variableninitialisierung
    End;
In Java und C# ist es möglich und funktioniert auch.

Antworten