| 
| Autor | Beitrag |  
| LittleBen 
          Beiträge: 258
 Erhaltene Danke: 4
 
 Win 7, Mac OS
 Delphi 7
 
 | 
Verfasst: Do 17.10.13 19:50 
 
Hallo,
in der Schule behandeln wir zurzeit das Thema 3-Schichtenmodell in Java, also GUI,Steuerung und Daten.
 Jetzt meine Frage: ist das Java-Spezifisch oder handhabt man das in Delphi auch so? Hab meine Projekte bis jetzt immer komplett anders gestaltet...halte es aber für eine gute Idee.
 Und noch eine frage: Wie löst man die Kommunikation zwischen den verschiedenen Schichten? Ich würde es, um den Code noch mehr zu verallgemeinern, alles mit Events machen. Also die GUI kennt die Steuerung, aber die Steuerung nicht die GUI. Die Steuerung löst nur Events aus, die beim Kreieren mitgehlieft wurden. Die GUI  reagiert dann darauf. Wie löst man das professionel, nach der alten delphischen Art?
 
 Viele Grüße
 Littleben
 |  |  |  
| jaenicke 
          Beiträge: 19326
 Erhaltene Danke: 1749
 
 W11 x64 (Chrome, Edge)
 Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
 
 | 
Verfasst: Do 17.10.13 20:46 
 
Das macht man in Delphi ähnlich. Ob nun GUI, Steuerung und Daten die beste Aufteilung ist, sei dahingestellt, aber prinzipiell eine Abtrennung mindestens der GUI ist immer sinnvoll.
 Ich halte in Delphi Interfaces für am sinnvollsten. Mit Events programmierst du dich eher tot. Mit Interfaces registrieren sich die einzelnen Teile gegenseitig und fertig.
 |  |  |  
| LittleBen  
          Beiträge: 258
 Erhaltene Danke: 4
 
 Win 7, Mac OS
 Delphi 7
 
 | 
Verfasst: Do 17.10.13 21:10 
 
Mhm, wie würde das mit den Interface dann in etwas aussehen?
 Angenommen man macht die GUI und Steuerung in eine Klasse (nur zur Übersichtlichkeit):
 												| 1:2:
 3:
 4:
 5:
 6:
 7:
 8:
 9:
 10:
 11:
 12:
 13:
 14:
 15:
 16:
 17:
 18:
 19:
 20:
 21:
 22:
 23:
 24:
 25:
 26:
 27:
 28:
 29:
 30:
 31:
 
 | unit Unit1;
 interface
 
 uses
 
 
 type
 TMyControl = class
 private
 procedure DownloadSomeData;
 public
 
 end;
 
 type
 TMyGUI = class(TForm)
 private
 FMyControl: TMyControl;
 public
 
 end;
 
 var
 GUI: TGUI;
 
 implementation
 
 {$R *.dfm}
 
 end.
 |  Wie würdest du hier die Kommunikation gestalten, wenn die GUI die Methode DownloadSomeData aus dem MyControl-Objekt aufruft, und dieses dann die Daten auf die GUI schreiben soll (kein Thread, und auch keine Rückgabewert    ). |  |  |  
| jaenicke 
          Beiträge: 19326
 Erhaltene Danke: 1749
 
 W11 x64 (Chrome, Edge)
 Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
 
 | 
Verfasst: Do 17.10.13 22:22 
 
Ein vollständiges Beispiel, nicht sonderlich schön, aber es sollte das Prinzip zeigen: 												| 1:2:
 3:
 4:
 5:
 6:
 7:
 8:
 9:
 10:
 11:
 12:
 13:
 14:
 15:
 16:
 17:
 18:
 19:
 20:
 21:
 22:
 23:
 24:
 25:
 26:
 27:
 28:
 29:
 30:
 31:
 32:
 33:
 34:
 35:
 36:
 37:
 38:
 39:
 40:
 41:
 42:
 43:
 44:
 45:
 46:
 47:
 48:
 49:
 50:
 51:
 52:
 53:
 54:
 55:
 56:
 57:
 58:
 59:
 60:
 61:
 62:
 63:
 64:
 65:
 66:
 67:
 68:
 69:
 70:
 71:
 72:
 73:
 
 | program Project17;
 uses
 Vcl.Forms,
 System.Generics.Collections,
 Unit9 in 'Unit9.pas' ;
 
 {$R *.res}
 
 type
 TAppController = class(TInterfacedObject, IAppController)
 private
 var
 FGUIList: TList<IMyGUI>;
 public
 constructor Create;
 destructor Destroy; override;
 procedure RegisterGUI(const AGUI: IMyGUI);
 procedure UnregisterGUI(const AGUI: IMyGUI);
 procedure DisplayText(const AValue: string);
 procedure TextEntered(const AValue: WideString);
 end;
 
 
 
 constructor TAppController.Create;
 begin
 FGUIList := TList<IMyGUI>.Create;
 end;
 
 destructor TAppController.Destroy;
 begin
 FGUIList.Free;
 inherited;
 end;
 
 procedure TAppController.DisplayText(const AValue: string);
 var
 CurrentGUI: IMyGUI;
 begin
 for CurrentGUI in FGUIList do
 CurrentGUI.DisplayText(AValue);
 end;
 
 procedure TAppController.RegisterGUI(const AGUI: IMyGUI);
 begin
 if not FGUIList.Contains(AGUI) then
 begin
 AGUI.RegisterController(Self);
 FGUIList.Add(AGUI);
 end;
 end;
 
 procedure TAppController.TextEntered(const AValue: WideString);
 begin
 DisplayText(AValue);
 end;
 
 procedure TAppController.UnregisterGUI(const AGUI: IMyGUI);
 begin
 FGUIList.Remove(AGUI);
 end;
 
 var
 MyController: IAppController;
 begin
 MyController := TAppController.Create;
 Application.Initialize;
 Application.MainFormOnTaskbar := True;
 Application.CreateForm(TForm9, Form9);
 MyController.RegisterGUI(Form9);
 Application.Run;
 end.
 |  												| 1:2:
 3:
 4:
 5:
 6:
 7:
 8:
 9:
 10:
 11:
 12:
 13:
 14:
 15:
 16:
 17:
 18:
 19:
 20:
 21:
 22:
 23:
 24:
 25:
 26:
 27:
 28:
 29:
 30:
 31:
 32:
 33:
 34:
 35:
 36:
 37:
 38:
 39:
 40:
 41:
 42:
 43:
 44:
 45:
 46:
 47:
 48:
 49:
 50:
 51:
 52:
 53:
 54:
 55:
 56:
 57:
 58:
 59:
 60:
 
 | unit Unit9;
 interface
 
 uses
 Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
 Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;
 
 type
 IMyGUI = interface;
 
 IAppController = interface
 procedure TextEntered(const AValue: WideString);
 procedure RegisterGUI(const AGUI: IMyGUI);
 end;
 
 IMyGUI = interface
 procedure RegisterController(const AController: IAppController);
 procedure DisplayText(const AValue: WideString);
 end;
 
 TForm9 = class(TForm, IMyGUI)
 Memo1: TMemo;
 Memo2: TMemo;
 Button1: TButton;
 procedure Button1Click(Sender: TObject);
 private
 var
 FController: IAppController;
 protected
 procedure RegisterController(const AController: IAppController);
 procedure DisplayText(const AValue: WideString);
 end;
 
 var
 Form9: TForm9;
 
 implementation
 
 {$R *.dfm}
 
 
 
 procedure TForm9.Button1Click(Sender: TObject);
 begin
 if Assigned(FController) then
 FController.TextEntered(Memo2.Text);
 end;
 
 procedure TForm9.DisplayText(const AValue: WideString);
 begin
 Memo1.Text := AValue;
 end;
 
 procedure TForm9.RegisterController(const AController: IAppController);
 begin
 FController := AController;
 end;
 
 end.
 |  In einem echten Programm gehören die Klassen und Interfaces natürlich in eigene Units usw., wie gesagt, nur ein ganz schnelles Beispiel...
 Architektur:
 Die GUI wird beim Controller angemeldet, der Controller meldet sich bei dieser Registrierung wiederum bei der GUI an. Dazu kann dann ebenso vom Controller aus noch der Datenteil kommen. |  |  |  
| LittleBen  
          Beiträge: 258
 Erhaltene Danke: 4
 
 Win 7, Mac OS
 Delphi 7
 
 | 
Verfasst: Fr 18.10.13 15:03 
 
Vielen Dank für das Beispiel!
 Die Interfaces kommen dann in eine eigene Unit. Wie wird diese so standardmäßig genannt?
 		                       Delphi-Quelltext 
 									| 1:2:
 
 | typeIMyGUI = interface;
 |   Ich nehme mal an, diese Zeile war ein Versehen? |  |  |  
| jaenicke 
          Beiträge: 19326
 Erhaltene Danke: 1749
 
 W11 x64 (Chrome, Edge)
 Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
 
 | 
Verfasst: Fr 18.10.13 15:15 
 
	  |  LittleBen hat folgendes geschrieben  : |  	  | Die Interfaces kommen dann in eine eigene Unit. Wie wird diese so standardmäßig genannt? | 
 Zum Beispiel kannst du das in einen Unterordner Interfaces legen und die Units genauso wie die Interfaces nennen. Also Zum Beispiel Littleben.Interfaces.MyGUI für das Interface IMyGUI. Wenn du es weniger modular haben möchtest, kannst du auch die Interfaces in einer eigenen Interface-Unit zusammen lassen, aber ich finde das etwas unübersichtlich.
 Bei deinem Delphi 7 weiß ich nicht, ob die Punkte im Unitnamen überall funktionieren. Das konnte das zwar schon, aber ich weiß nicht, ob überall.
 Ich würde jedenfalls entweder eine Sammelunits für die Interfaces oder Units, die mit Interfaces und ggf. einem Zusatz genauso wie das Interface heißen nehmen.
 	  |  LittleBen hat folgendes geschrieben  : |  	  | 		Ich nehme mal an, diese Zeile war ein Versehen?                       Delphi-Quelltext 
 									| 1:2:
 
 | typeIMyGUI = interface;
 |  | 
 Nein, eine forward Deklaration. Das danach folgende Interface benötigt das Interface IMyGUI, deshalb muss vorher schon einmal deklariert werden was das für ein Typ ist, nämlich ein Interface.
 In deinem echten Programm sollten solche Rückwärtsreferenzen nicht nötig sein, das lag nur daran, dass das Beispiel so kompakt bleiben sollte. |  |  |  
| LittleBen  
          Beiträge: 258
 Erhaltene Danke: 4
 
 Win 7, Mac OS
 Delphi 7
 
 | 
Verfasst: Mi 23.10.13 18:26 
 
Ich habe das gerade mal unter XE5 (bin jetzt auch auf dem neusten Stand    ) mit Firemonkey auspobiert. Dort bekomme ich eine Access Violation  sobald ich das Formular vor Application.Run benutze.
 Wie muss ich es dann anstellen? |  |  |  
| jaenicke 
          Beiträge: 19326
 Erhaltene Danke: 1749
 
 W11 x64 (Chrome, Edge)
 Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
 
 | 
Verfasst: Mi 23.10.13 18:34 
 
Naja, erstellt sein muss es. Das Hauptformular mit Application.FormCreate, die anderen direkt. Ohne Quelltext kann man dazu aber nicht viel sagen. |  |  |  
| LittleBen  
          Beiträge: 258
 Erhaltene Danke: 4
 
 Win 7, Mac OS
 Delphi 7
 
 | 
Verfasst: Mi 23.10.13 18:44 
 |  |  |  
| jaenicke 
          Beiträge: 19326
 Erhaltene Danke: 1749
 
 W11 x64 (Chrome, Edge)
 Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
 
 | 
Verfasst: Mi 23.10.13 21:09 
 
Das sieht erst einmal nicht schlecht aus. Häng am besten mal das ganze Projekt an, viel ist da ja vermutlich ohnehin noch nicht drin. |  |  |  
| LittleBen  
          Beiträge: 258
 Erhaltene Danke: 4
 
 Win 7, Mac OS
 Delphi 7
 
 | 
Verfasst: Do 24.10.13 11:32 
 
Okay, im Anhang mein Testprojekt. Muss ein saublöder Fehler sein     Wenn ich testweise soetwas einbau:
 		                       Delphi-Quelltext 
 									| 1:2:
 3:
 4:
 5:
 6:
 7:
 8:
 9:
 
 | var Controller: IMyController;begin
 Controller:= TMyController.Create;
 Application.Initialize;
 Application.CreateForm(TF_Main, F_Main);
 Application.Run;
 Controller.RegisterGUI(F_Main);
 Application.ProcessMessages;
 Sleep(1000);
 |  dann funktioniert es, aber eben erst nach dem Schliesen...
 EDIT: Hab das Problem gefunden gefunden... nach dem CreateForm muss noch folgendes eingefügt werden: 
Application.RealCreateForms; Dann funktionierts!
Einloggen, um Attachments anzusehen!
 |  |  |  
| jaenicke 
          Beiträge: 19326
 Erhaltene Danke: 1749
 
 W11 x64 (Chrome, Edge)
 Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
 
 | 
Verfasst: Do 24.10.13 12:29 
 
Ok, das ist nur mit FireMonkey so, in der VCL wird das Formular auch direkt erzeugt, nicht erst beim Ausführen. |  |  |  
| LittleBen  
          Beiträge: 258
 Erhaltene Danke: 4
 
 Win 7, Mac OS
 Delphi 7
 
 | 
Verfasst: Do 24.10.13 14:19 
 
So ein scheeeiii....         Unter iOS darf ich die Forms nicht früher kreieren. Ich bekomme bei der Funktion function TPlatformCocoaTouch.CreateWindow(const AForm: TCommonCustomForm): TWindowHandle;  eine Access Violation Exception bei LOrientation := UIApp.statusBarOrientation;   Keine Ahnung was ich jetzt tun soll    |  |  |  
| jaenicke 
          Beiträge: 19326
 Erhaltene Danke: 1749
 
 W11 x64 (Chrome, Edge)
 Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
 
 | 
Verfasst: Do 24.10.13 14:59 
 |  |  |  
| LittleBen  
          Beiträge: 258
 Erhaltene Danke: 4
 
 Win 7, Mac OS
 Delphi 7
 
 | 
Verfasst: Do 24.10.13 16:33 
 
 jaenicke  hat mal wieder zugeschlagen      Funktioniert. 
 Nur noch aus Interesse: Gäbe es noch eine oder mehere Möglichkeiten das Proboblem zu lösen? Hörte sich so an als wüsstest du noch andere Wege. |  |  |  |