![]() |
OOP Problem: änderungen werden nicht übernommen
Hallo,
Ich habe jetzt etwas viel geschrieben ich hoffe das sich jemmand die mühe macht diese Frage durchzulesen und eine lösung für das "ausfürhlich" beschriebende problem zu finden *G* Vielen Dank im voraus. Ich möchte mir ein eigene "kleine" GUI schreiben. Die nur ein paar standart komponenten hat wie z.b. - Button - Edit - Formula ersteinmal, später kann ich sie ja noch erweitern. Ich habe mir jetzt einige gedanken gemacht für den Klassenaufbau und auch angefangen da bin ich leider auf unerwartete probleme gestoßen. Ich möchte ein obj per Create erstellen wie in der "Delphi GUI" und genau hier fangen die probleme an: ich wollte eine allgemine komponenten liste erstellen die habe ich in der Unit definiert:
Delphi-Quellcode:
dort sollen alle komponenten rein die mit Create erstellt werden.
var
GUI:TGUI; implementation TGUI sieht so aus:
Delphi-Quellcode:
das Stanadt obj von denn allen abgeleitet werden müssen damit es
TGUI = class
private public items:TObjectList; constructor Create; procedure Add(obj:TStdObj); procedure Del(Index:Integer); procedure Draw; end; funktioniert sieht so aus:
Delphi-Quellcode:
Jedes obj gehört zu einem Formual ohne gehts nicht:
TSTDObj = class
private public GFL:TMyCanvas; Sel:TStdObj; Namen:String; Caption:String; // Enhälst den Anzeige Text Hint:String; // Enhälst eine Genaue Beschreibung der Liste Parent:String; // Enthälst den Unterkomponente Typ1:String; // Benuterdefniert Visible:Boolean; // Sichtbar oder unsichtbar ShowHint:Boolean; // Beschreibung anzeigen oder nicht anzeigen isStdList:Boolean; // Fügt in eine Eigne Liste ein die jede komponente hat Typ:Integer; // Benuterdefniert x,y,w,h,r:Integer; // Position(x,y) Größe(w,h) ObjTyp:Integer; // Kreis oder Rechteck absX,AbsY:Integer; // Abstand zum Rand onMouseMove:TMouseMove; onMouseUp:TMouseUp; onMouseDown:TMouseDown; onMouseLave:TMouseLave; onKeyDown:TKeyDown; onKeyPress:TKeyPress; onKeyUp:TKeyUp; constructor Create(h:HWND;obj:Tobj); procedure Draw; end;
Delphi-Quellcode:
Das Problem ist jetzt wenn ich ein variable änder z.b. den Caption wird dies leider nicht in die obj liste übernommen.
TFormula = class(TStdObj)
private MoveT:Integer; public Titel_W,Titel_H,Titel_X,Titel_Y:Integer; f:TForm; EnabledColor:TColor; constructor Create(Form:TForm; pCaption:String); procedure Draw; procedure Click(px,py:Integer;Button: TShiftState); procedure MoveUp(px,py:Integer;Button: TMouseButton); end; implementation constructor TFormula.Create(Form:TForm;pCaption:String); begin inherited Create(Form.Handle,self); EnabledColor:=clRed; f:=Form; x:=0; y:=0; w:=form.Width; h:=Form.Height; Titel_W:=w; Titel_H:=20; Titel_X:=0; Titel_Y:=0; Form.BorderStyle:=bsNone; Form.Position:=poDesigned; Caption:=pCaption; MoveT:=-1; end; // Create // aufruf procedure TForm1.FormCreate(Sender: TObject); var Button:TMyButton; begin f:=TFormula.Create(Form1,'Dies ist ein kleiner test'); f.namen:='Form1'; button:=TMyButton.Create(Form1.Handle,button); button.Caption:='Hallo'; button.Namen:='button1'; button.x:=10; button.y:=10; Button.w:=10; Button.h:=10; f.absX:=2; f.absY:=2; end; und ich möchte gerne das diese auch übernommen werden. d.h. alle variablen die ich änder kann sollen auto. in die obj liste übernommen werden. ich dachte mir das ein "zeiger" oder was änliches auf das gerade erstelle obj zeigt. Wie z.b. mit folgedner defniation:
Delphi-Quellcode:
jetzt wird ja test mit test3 verküpft und so dachte ich mir das in meinem problem auch.
test:=test3
Das ganze soll wie in der Delphi GUI ablaufen. Dachte ich mir. ich hoffe ihr versteht worauf ich hinaus möchte. Anmerkung: ich schreibe zwar schon seit ca 5-7 Jahren in Delphi meine Programme aber mit der OOP habe ich bis noch nicht so ausführlich gearbeitet d.h. Ich habe schon klassen defniniert und ereignisse und eigenschaften erstellt nur was ich bis jetzt noch nicht getan habe ist mit vererbungen zu arbeiten also das "eigentliche" oop. |
Re: OOP Problem: änderungen werden nicht übernommen
Dazu rate ich dir mal ein
![]() Und nun noch zur Deutschen Sprache: Die Art zu Stehen hat nichts mit dem Standard zu tun. Warum schreiben eigentlich 70% aller Deutschen das Wort immer falsch. Irgendwas muss da in den Schulen wohl falsch laufen. Vielleicht sollte man der Dudenkommision auch mal die "Art zu Stehen" als alternative für "Standard" vorschlagen. Auch wenn man in der gesprochenen Sprache bei "Formular" das "r" verschluggt, wird es trotzdem geschrieben :wink: |
Re: OOP Problem: änderungen werden nicht übernommen
Vielen Dank. Das tutor werde ich mir gleich mal durchlesen. evlt. gibt es ja anregungen für die Klassenstrucktur.
Zitat:
|
Re: OOP Problem: änderungen werden nicht übernommen
ich habe mir das Tutor durchgelesen und wollte eine Klassenstruckur schreiben die sieht jetzt so aus. dazu habe ich einige fragen:
Delphi-Quellcode:
1: Eigenschafen:
unit uStdObj;
interface type TStdObj = class private FName:String; // Enhält den Namen des Obj FCaption:String; // Enhält das was Angezeigt wird FTag:Integer; // unBelengt Fx:Integer; // die X Position vom OBJ Fy:Integer; // die Y Position vom ObJ fw:Integer; // Die Breite vom Obj Fh:Integer; // die Höhe vom Obj procedure SetCaption(Caption:String); procedure SetnNmen(Namen:String); public constructor Create(obj:TStdObj); destructor Free; procedure Draw published property Name:string read fName write fName; property Caption:string read fCaption write fCaption; end; implementation constructor TStdObj.Create(obj:TStdObj); begin end; // Create destructor TStdObj.Free; begin end; // Free procedure TStdObj.SetCaption(Caption:String); begin fCaption:=Caption; Draw; end; // SetCaption procedure TStdObj.SetNamen(Namen:String); begin fNamen:=Namen; Draw; end; // SetNamen end. Ich möchte gerne das bei jede änderung eine eigenschft die procedure Draw danach ausgeführt wird. Muss ich das denn so "aufwendig" schreiben wie ich das mit namen und Caption gemacht habe, oder kann ich das auch etwas kürtzer schreiben. 2: Strucktur: Ist die strucktur bis jetzt sinvoller als die "alte" ? |
Re: OOP Problem: änderungen werden nicht übernommen
Zitat:
Zitat:
In den Aufruf des Konstruktors sollte unbedingt immer als erstes ein Aufruf des Vorgänger Konstruktors (analog beim Destruktor). Und dein Destruktor sollte Destroy heißen (und ein override bekommen). Free solltest du nicht überschreiben, da Free nicht mehr macht als zu schauen ob die Instanz noch existiert (Referenz <> nil) und dann Destroy aufruft. Wenn dies die Basisklasse ist, von denen andere Objekte abgeleitet werden sollen, dann solltest du zudem darüber nachdenken, die setter lieber protected zu deklarieren (selbes würde ich mit draw machen). Für Draw wäre dann noch interessant wohin du zeichnen lassen möchtest. Ach ja, einige Methoden (hier natürlich nur draw) solltest du in der Basisklasse einfach mal abstract lassen. Ich weiß nicht ob du in deinem Tut auch schon was über Interfaces und abstrakte Klassen gelesen hast, aber die sind in der OOP von hoher Bedeutung, da du mit ihnen sehr viel sehr elegant lösen kannst. Wie gesagt, dein Ansatz ist schon deutlich besser als der erste, aber ich denke du wirst noch viel lernen (während der Entwicklung). Wichtig ist es halt, möglichst gut vorbereitet zu starten, Fehler vermeiden kostet immer viel viel weniger als welche Nachträglich zu beseitigen. Gruß Der Unwissende |
Re: OOP Problem: änderungen werden nicht übernommen
was meisnt du mit "setter" ?
Zitat:
Zitat:
ich möchte auch nur das obj neu zeichen lassen was sich gerade ändert. Zitat:
du möchte eine grafik engine schreiben und möchtes verschiende grafik system verwenden z.b. openGL, DX, Canvas, etc. aber bei meiner GUI wüste ich jetzt nicht wo es da verwendung finden sollte. eine frage habe ich aber noch: verwaltung der obj. ich möchte gerne das jedes obj z.b. ein panel sein obj. selsbt verwalten kann dies soll über ein schalter gemacht werden. d.h. wenn diese schalter auf True ist soll die eigene liste verwendet werden und wenn dierser auf False ist(standart einstellung) soll es in die allgemeine liste eingefügt werden. Problem ist hier die umsetzung. Ein kleines beispiel währe nicht schlecht. Ich wollte wohl TObjectList nehmen.. Da dies mein erstes richtiges OOP programm ist wollte ich es gleich richtig planen damit ich nicht alles von vorne schreiben muss weil ich festelle das irgenwas nicht funktioniert. Das währe ja ärgerlich. |
Re: OOP Problem: änderungen werden nicht übernommen
das ist die "neue klasse" habe ein paar änderung gemacht die ich übersehen hatte :oops:
Delphi-Quellcode:
ps: warum wird Name als schlüsswort hier angezeigt und nicht als normale variable ?
TStdObj = class
private FName:String; // Enhält den Namen des Obj FCaption:String; // Enhält das was Angezeigt wird FTag:Integer; // unBelengt Fx:Integer; // die X Position vom OBJ Fy:Integer; // die Y Position vom ObJ fw:Integer; // Die Breite vom Obj Fh:Integer; // die Höhe vom Obj procedure SetCaption(Caption:String); procedure SetNamen(Namen:String); public constructor Create(obj:TStdObj); destructor Free; procedure Draw; published property Name:string read fName write SetNamen; property Caption:string read fCaption write SetCaption; end; |
Re: OOP Problem: änderungen werden nicht übernommen
Zitat:
Deswegen sind Variablen in der OOP eigentlich immer privat und du greifst eigentlich nie direkt auf sie zu (es lässt sich immer vermeiden). Statt dessen benutzt du eine Methode, die einen Wert setzt (Setter) und eine Methode die dir einen Wert liefert (Getter). Natürlich wird dir der Setter häufiger begegnen (hier prüfst du beim setzen ob der Wert gültig ist). Aber auch getter machen Sinn, wenn du zum Beispiel eine Liste von Zahlen hast und die größte Zahl bekommen möchtest, könntest du entweder immer die größte Zahl in einer Variablen speichern oder du sortierst die aufsteigend und nimmst das letzte Element oder du durchläufst die gesamte Liste und suchst das Größte. Wie du siehst leisten alle Methoden genau das gleiche, doch warum sollte es dich von aussen kommend interessieren? Du willst nur das größte Element. Hast du jetzt eine Methode getGreatestOne, liefert die dir irgendwie das Größte Element (alles was du willst). In Delphi verbergen Properties nur den expliziten Aufruf solcher Methoden (du kannst natürlich auch direkt die Variable schreiben oder lesen). Zitat:
Zitat:
Ein Interface ist erstmal nur eine Sammlung an Methoden. Du weißt nur durch die Dokumentation was die einzelnen Methoden machen sollen und du weißt was für Argumente sie bekommen. Das wars. Ein Interface implementiert aber keine dieser Methoden. Jede Klasse kann von genau einer Klasse erben, sie kann aber zusätzlich noch beliebig viele Interfaces implementieren. Ein Interface zu implementieren heißt dabei, dass jede abstrakte Methode des Interfaces in der Klasse implementiert werden muss. Implementiert also eine Klasse ein Interface, so wird dir zugesichert, dass diese Klasse alle Methoden des Interface besitzt. Das eigentlich Wichtige an diesen Dingern ist eben diese Zusicherung. Wenn du dein Programm erweiterst, möchtest du nicht für jede Erweiterung das Rad neu erfinden (nicht in der OOP). Also versuchst du den gemeinsamen Nenner zu finden und zu verwenden. Wichtig ist, dass jede Klasse immer die Eigenschaften ihrer Vorfahren und der implementierten Interfaces hat. Ein Interface entspricht weitgehend einer abstrakten Klasse, allerdings besitzt ein Interface ausschließlich abstrakte Methoden (eine abstrakte Klasse besitzt nur mindestens eine abstrakte Methode). Das ganze mal etwas deutlicher an einem Beispiel:
Delphi-Quellcode:
Ok, kein großartiges Beispiel, aber soll ja auch nur kurz etwas zeigen. Hier siehst du erstmal dass du zwei verschieden Objekte mit unterschiedlichen Eigenschaften hast. Ein TDrawableButton hat eine Methode OnClick, aber eben keine Farbe, diese hat dann aber ein TDrawablePanel. Trotzdem sind beide vom Typ TDrawable, besitzen also beide eine Methode draw zum Zeichnen und bei beiden kann man die X und Y Position setzen. In diesem Beispiel wird der Sinn vielleicht noch nicht all zu klar, aber vielleicht siehst du schon, dass du nun ein beliebiges TDrawable auf immer den selben Canvas zeichnen könntest. Dazu übergibst du nur noch ein TDrawable, du weißt ja dass es ein Draw hat. Diesem Draw übergibst du den Canvas auf den gezeichnet werden kann und dich interessiert es nicht ob es sich um ein TDrawableButton, TDrawablePanel oder gar ein TDrawableHastDuNichtGesehen handelt.
type
TDrawable = Interface procedure setPosX(const Position : Integer); procedure setPosY(const Position : Integer); procedure Draw(const Canvas : TCanvas); end; TDrawableButton = class(TInterfacedObject, TDrawable) protected procedure OnClick; public procedure setPosX(const Position : Integer); procedure setPosY(const Position : Integer); procedure Draw(const Canvas : TCanvas); end; TDrawablePanel = class(TInterfacedObject, TDrawable) private FPosX, FPosY : Integer; FColor : TColor; protected procedure setColor(const Color : TColor); public procedure setPosX(const Position : Integer); procedure setPosY(const Position : Integer); procedure Draw(const Canvas : TCanvas); property Color : TColor read FColor write setColor; end; .... procedure doFoo; var Drawable : TDrawable; begin DrawAble := TDrawablePanel.Create; // Achtung, DrawAble hat nur die Eigenschaften des Inteface! // also nur die Methoden setPosX/Y und Draw DrawAble.Draw(Form1.Canvas); ... end; Genauso leicht kannst du so ein TNotifyable definieren, dass eine Nachricht annimmt. Wenn du nun ein Hauptinstanz hast, die eine Liste von TNotifyalbes verwaltet, dann müsstest du bei einem Ereignis nur jedem dieser Objekte die Nachricht übergeben... Hoffe du siehst was ich meine, ist wirklich wichtig in der OOP. Kommen neue Klassen hinzu, ist dir das egal. Implementieren sie ein Interface, stellen sie mindestens diese Funktionen zur Verfügung und mehr interessiert dich dann garnicht. Zitat:
Gruß Der Unwissende |
Re: OOP Problem: änderungen werden nicht übernommen
Zitat:
z.b.: 2 Diese Komponenten müssen neugezeichnet werden a: wie finde ich herraus welche das sind ? b: wie kann ich auf diese zugreifen ? hätte ich eine liste mit komponenten könnte ich ja einfach schauen wo sollgeändert werden auf True steht, weißt du was ich damit meine ? und mit selber verwalten dachte/meine ich folgendes: Unter Delphi gibt es ja eine "Lange" liste in mit komponenten die ich auf dem Formular habe, richtig ? d.h. alle komponenten die auf dem panel sind sind auch in der "allgemeine" liste. geau das wollte ich ändern. alle komponenten die komponenten aufnehmen soll sollen auch über eine eigene liste verfügen. Natürlich währe das durchsuchen wird schwrig, z.b. wenn ich eine bestimmte komponente suchen muss dann muss ich ja ersteinaml die 1. liste durchsuchen und dann die weitern aber welche ? da fällt mir im moment nur eine lösung ein: in der 1. liste steht ein verweis auf die andern listen. das kann ich ja beim installsiern feststellen. Weißt du wie ich es mir vorstelle ? oder mal andres(genau das gleiche problem nur anderes beschrieben): Ich habe die 20 Komponenten und möchte auf die 2 zugreifen z.b. über FindKomponente(2) oder FindKomponente('Zweitekomponente'); Vielen dank für deine Tipps. Nur das mit den interface verstehe ich immer noch nicht so ganz. scheint aber ein mächtige funktion zu sein in der OOP. Das mit der Draw funktion wollte ich auch indrect nutzen. weil ich nutze für die Grafik dastellung nicht canvas sonder direkt die GDI habe da eine unit gefunden: ![]() ich habe jedoch ein kleine extra unit geschrieben die die verwendung vereinfacht *G* mit Setter und Getter meinst du sowas: Setter=procedureen die was Setzten Getter=funktionen |
Re: OOP Problem: änderungen werden nicht übernommen
Ok,
hier wären wir schon fast wieder bei den Interfaces. Ist eigentlich gar nicht so schwer, du musst dir nur etwas mehr überlegen welche Klassen was gemeinsam haben. Ich hoffe ich bin hier nicht zu sprunghaft oder unverständlich oder so, beschwer dich einfach immer wenn das der Fall ist und frag nach! Ist wichtig und richtig! Da ich nicht weiß wie gut dein Tutorial zu OOP war (und ehrlich gesagt hab ich echt einige gebraucht um den Sinn zu verstehen), möchte ich nochmal ein wenig auf die Ideen eingehen. Die OOP ist eigentlich nur ein einfacher Versuch, das reale Leben auf die Programmierung abzubilden. Unnötig zu sagen, dass es nicht trivial ist. Bei der Beobachtung des "realen Leben" viel auf, dass wir alles in Klasen aufteilen können. Diese Unterteilungen kann man dann auch noch verfeinern (also sowas wie Tier -> Säugetier -> Affe -> Schimpanse -> Chita (wie auch immer man die schreibt)). Man weiß also sehr viel über einen sehr speziellen Schimpansen, aber vor allem auch, dass Chita ein Schimpanse ist. Du weißt also das Chita Fell hat, ein Menschenaffe ist, Bananen ist, ... Das kannst du nicht über alle Säugetiere sagen, aber alles was du über ein Säugetier sagen kannst gilt halt auch für Chita. Wichtig ist es also, dass du immer alle Eigenschaften in einer Verfeinerung bei behälst. Die andere wichtige Sache dieser Unterteilung ist, dass ich auch andere Säugetiere haben kann (Tier -> Säugetier -> Bär -> Balu -> ...). Hab ich ein Säugetier, weiß ich dass es Sauerstoff zum atmen braucht, das gilt sicherlich für Chita und Balu, aber eben auch für jedes andere Säugetier. Aber gilt dass auch für jedes Tier? (Tier -> Fisch -> Nemo) Wohl eher nicht. Also fasse ich alles nach bestimmten Eigenschaften zusammen und kann dabei beliebig verfeinern. In der OOP unterscheidet man nicht die Stufe der Verfeinerung, alles ist einfach ein Klasse (nichts Familie, Art, Gattung, ...). Alles was existiert ist dann eine Instanz. Etwas anschaulicher kannst du sagen, Klassen sind der Bauplan, Instanzen/Objekte sind das Gebaute. Also sind Tier, Fisch, Säugetier, Affe, ... alles nur Klassen die gewisse Eigenschaften festlegen. Chita, Nemo und Balu sind hingegen Instanzen, sie wurden nach dem jeweiligen Bauplan angefertigt. Natürlich kann man beliebig viele Instanzen einer Klasse anlegen (z.B. könnte auch Charlie ein Schimpanse sein). Das ist der eine Teil der OOP. Du erstellst einfach immer einen Bauplan, der genau die Eigenschaften von etwas festlegt. Aber mehr hast du nicht, nur den Bauplan. Beim Programmstart erstellst du dann aus den einzelnen Bauplänen konkrete Instanzen. Dein Programm ist dabei ihre Welt. Eine Instanz führt immer ein begrenztes Leben. Sie kann erst nach der Welt (dem Programmstart) entstehen und endet auch mit der Welt (Programmende). Länger kann nichts leben, aber früher sterben geht immer (Destruktor aufruf). Jede Instanz führt dabei auch ein ganz eigenes Leben und kann seine Eigenschaften individuell ändern. Aber jede Instanz hat halt auch nur genau die Eigenschaften, die in der Klasse stehen. Da jede Instanz ihr eigenes Leben hat, interessieren sich Instanz erstmal nicht weiter führ einander, sie leben halt irgendwo auf der Welt. Was genau in ihnen vorgeht weiß man nicht, interessiert einen aber auch nicht. Wenn man eine Instanz findet, gibt es die Möglichkeit mit dieser zu kommunizieren. Dabei ist aber (durch die Klasse) festgelegt, wie diese Kommunikation aussieht. Alles was öffentlich ist (public oder published) kann jeder zur Kommunikation benutzen. Dinge die privat sind, kann nur die Instanz selbst sehen, Dinge die geschützt sind (protected), sehen nur Nachfahren oder Instanzen der gleichen Klasse. Die Kommunikation entspricht also dem Aufruf von Methoden (proceduren / funktionen). Das war's eigentlich schon so ziemlich. Hoffe es war soweit verständlich. Ist wie gesagt nur grob die Grundidee. Daraus hervor gehen tun die typischen Punkte, was OOP möchte (die findest du mit google). Was du jetzt machen möchtest lässt sich geradezu ideal in OOP modellieren. Du hast ein Hauptformular (dein GUI). Hier möchtest du Elemente platzieren. Diese Elemente sind sichtbar. Einige von ihnen (und das Hauptformular) können andere Elemente aufnehmen. Das sind alles Eigenschaften. Du musst jetzt nur noch die Eigenschaften geschickt zusammen fassen. Es sollte immer alles was zusammen gefasst werden kann auch zusammen gefasst werden (natürlich kann man alles übertreiben, meine implizit natürlich sinnvoll). Du hast hier also einmal eine Klasse von Objekten, die Elemente aufnehmen können. Dann hast du eine Klasse von Elementen die gezeichnet werden können. Eventuell hast du ja auch noch eine Klasse von Elementen, die nicht gezeichnet werden können. Nehmen wir nur die ersten beiden Eigenschaften. Du hast also dein Hauptformular, dass kann Objekte aufnehmen. Die Objekte, die du darauf ablegst können alle gezeichnet werden, aber nur einige davon können Objekte aufnehmen. Mit zwei Klassen ist es etwas schwer Interfaces zu rechtfertigen, aber ich möchte hier noch nichts als Beispiel konstruieren, verwirrt wohl eher. Die Idee eines Interfaces noch einmal: Du könntest jetzt einfach Eigenschaften in ein Interface packen. Du tust dort einfach alles rein, was es an Gemeinsamkeiten gibt. Objekte aufnehmen bringt nur etwas, wenn diese Objekte auch wieder entfernt werden können. Und wenn du suchen möchtest, musst du natürlich alle Objekte bekommen können. Das alles ist doch super und daraus bauen wir einfach mal ein Interface (einen Bauplan, aus dem aber nichts direkt gebaut werden kann).
Delphi-Quellcode:
Ok, dies wäre einfach nur eine Beschreibung von Eigenschaften. Alles was IKannObjekteAufnehmen (führendes I weil Interface) implementiert hat diese drei Methoden. Was genau ein Objekt macht, wenn ich fuegeObjektHinzu aufrufe ist mir hier vollkommen egal.
type
IKannObjekteAufnehmen = Interface procedure fuegeObjektHinzu(const neuesObjekt : TObject); procedure entferneObjekt(const Objekt : TObject); function getListeDerObjekte : TObjectList; // entschuldige das get, aber ist ja fast Konvention end; Am Beispiel der Säugetiere, jedes Säugetier hat eine Lunge um zu atmen, aber jedes Säugetier atmet unterschiedlich. Was in der Lunge passiert und wie groß das Lungenvolumen ist und und und ist mir egal. Hättest du hier eine Klasse, müsstest du für die Klasse die Implementierung angeben. Das hier kannst du in eine eigene Datei in den Interface-Teil schreiben und die Datei wäre fertig. Die andere Eigenschaft ist natürlich das man etwas zeichnen kann. Dazu benötigt man nur eine Funktion, die für das zeichnen zuständig ist. Also
Delphi-Quellcode:
Ok, jetzt siehst du gleich (ausnamhsweise beabsichtigt) einen klassischen Designfehler. Es würde so funktionieren, wie es hier steht, aber IKannObjekteAufnehmen kann halt jedes Objekt aufnehmen, ohne Einschränkung. Du möchtest aber doch eigentlich nur deine (zeichenbaren) Objekte aufnehmen. Hm, wenn wir also erst festgelegt hätten, was zeichenbar ist...
type
IKannGezeichnetWerden = Interface procedure draw; end; Also erst letzte Deklaration von IKannGezeichnetWerden erstellen und dann :
Delphi-Quellcode:
Jetzt übergibst du nur noch IKannGezeicnetWerden-Objekte. Das heißt alles was du übergibst hat immer die Methode draw (du weißt nicht was sonst noch, aber die hat es).
type
IKannObjekteAufnehmen = Interface procedure fuegeObjektHinzu(const neuesObjekt : IKannGezeichnetWerden); procedure entferneObjekt(const Objekt : IKannGezeichnetWerden); function getListeDerObjekte : TObjectList; // entschuldige das get, aber ist ja fast Konvention end; Ja, jetzt siehst du vielleicht schon, warum ich vorhin über dein Hauptformular / die GUI nicht gesagt habe, dass sie zeichenbar ist. Das mag zwar sein, aber die möchtest du sicherlich nicht sich selbst hinzufügen können (und erst recht nicht einem Panel oder ähnlichem). Deine Verwaltung kannst du nun auf diese Art und Weise vornehmen. Du legst dir erst Interfaces mit den zusammengehörigen Eigenschaften an und implementierst diese dann. Wenn etwas ein Interface implementiert, kann es auch dort übergeben werden, wo ein solches Interface verlangt wird (wenn ich einen Affen will, ist Chita ok, auch wenn ich ein Säugetier will. Möchte ich aber einen Hund, tut es Chita nicht, kein bellen, ...). Ich glaube das reicht erstmal. Hoffe habe hier nicht zuviel auf einmal gepostet, frag gerne nach! Gruß Der Unwissende |
Re: OOP Problem: änderungen werden nicht übernommen
Vielen dank für den versuch mir das interfase verständlich zu erklären. Aber ich finde ein interfase würde sich doch für eine funktion garnicht lohnen. dann müsten da auch variabln und sowas rein kommen.
Was klassen sind weiß ich inzwischen. Sie enthalten ein Bauplan nach diesem plan wird diese klase aufgabaut. Bis auf das interfase habe ich alles verstanden. das würde ja beudeten das ich dem interface alles gebe was das standart objekt haben soll z.b. eine Lösch procedure eine Hinzufüge procedure eine Draw Procedure onDraw onAdd onDel die standart klasse also die 1. klasse von der alles gerebt werden muss würde dann die oben genanten funtkion enthalten und dann ihre eigenen wie z.b. Namen, Caption, X,Y,W,H und sowas. Ich muss sie auch nicht mehr defnieren wenn ich die klasse so erstelle: TStdObj = class(IInter) // TInter ist mal das interface und dieser klasse kann ich also noch weiter variabeln/Funktionen/Proceduren/Ereignise hinzufügen. Wenn ich das so machen wollte wie in Delphi d.h.
Delphi-Quellcode:
werden ja die änderungen übernommen weil name eine eigenschaft ist wie bekomme ich das auch hin.
var
b:TButton; begin b:=TButton.Create b.Name b.Top end; (Das war die eigentliche Frage*G*) Aber das beispiel mit den Tieren war auch nicht schlecht in den meisten beispieln geht es um Autos. Müste dann bei den Aurufe von Create auch alles in eine liste hinzugefügt werden oder kann ich das anderes lösen und beim zeichnen ? Aber eins hat mir dein Text verständlich gemacht: das Formular ist die wichtiges Klasse bei Komponenten d.h. wenn kein Form erstellt wurde dann sollen auch keine komponenten installisiert werden. Gemeinsame funktionen währen ja die alle komponenten haben sollen die der GUI angehöhren z.b. alle Edit, Button, Label, Menus, Listenboxen und soweiter müsten also diese eigenschaften haben: - Namen, Caption - x,y,w,h,tag(sollte ein array evlt. sein),ax,ay - Parent(ist der wichtig ?) - Destroy, Create, Draw Wie geht es jetzt weiter ? das Fenster muss also diese eigenschaften haben aber noch weitere wie z.b. die Titel Position und Titel Größe, Farbe und sowas halt. Sollen Scrollbalken angezeigt werden ? Soll die Größe automatisch berechnet werden ? Soll die position in der Mitte des Desktops sein ? und sowas. ich habe z.b. ein Formular und ein Button. beide stammen von StdObj ab und haben eine standart Draw funktion die auch ausgeführt werden sollte. Es muss ein rechteck gezeichnet werden in beiden fällen. Aber in ein Form muss ja noch ein line weiter oben gezeichnet werden als Titel(richtig ?) d.h. ich brauche für das Fenster auch eine eigene Draw funktion geht das überhaupt ? ich möchte das erst die standart funktion aufgerufen wird und sofern vorhanden die eigene die beim Form dabei sind denn beim Button brauche ich keine eigene Draw funktion. Weißt du was ich meine ? Vielen Dank für deine Mühe mir bei diesem schwirigen Problem zu Helfen. |
Re: OOP Problem: änderungen werden nicht übernommen
Liste der Anhänge anzeigen (Anzahl: 1)
Ich beziehe mich hauptsächlich auf das hier :
Zitat:
Formular mit Button und Edit :
Delphi-Quellcode:
Das Teil ist bereits umbenannt und wird mit Rechtsklick in die Objektablage verfrachtet. Ich brauche das nächste Formular, welches noch die Listbox und die Combobox erhalten soll, alles andere bleibt gleich.
unit Unit1;
interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs; type TGrundForm = class(TForm) Button1: TButton; Edit1: TEdit; private { Private-Deklarationen } public { Public-Deklarationen } end; var Form1: TForm1; implementation {$R *.dfm} end. Neu -> weitere, Formular suchen und unten vererben nicht vergessen ! Ich pappe die Listbox und die Combobox da drauf. Ergibt das :
Delphi-Quellcode:
Jetzt hat das Formular : Button, Edit (beide geerbt) und neu sind die Listbox und die Combobox. Das zweite Formular mache ich jetzt gelb und ganz klein Hier die DFM :
unit Unit2;
interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs; type TGrundForm2 = class(TGrundForm) ComboBox1: TComboBox; ListBox1: TListBox; private { Private-Deklarationen } public { Public-Deklarationen } end; var GrundForm2: TGrundForm2; implementation {$R *.dfm} end.
Delphi-Quellcode:
Wie man sieht habe ich den Button und das Edit ganz in die Ecke geschoben und die ganze Form ist nur noch 174 Pixel breit. Es werden also nur die Differenzen zum Vorgänger neu gespeichert. Alles andere bleibt ! Na gut noch Anhang.
inherited GrundForm2: TGrundForm2
Width = 174 Height = 226 Caption = 'GrundForm2' Color = clYellow OldCreateOrder = True PixelsPerInch = 96 TextHeight = 13 inherited Button1: TButton Left = 8 Top = 8 end inherited Edit1: TEdit Left = 8 Top = 40 end object ComboBox1: TComboBox Left = 8 Top = 72 Width = 145 Height = 21 ItemHeight = 13 TabOrder = 2 Text = 'ComboBox1' end object ListBox1: TListBox Left = 8 Top = 96 Width = 121 Height = 97 ItemHeight = 13 TabOrder = 3 end end |
Re: OOP Problem: änderungen werden nicht übernommen
Hi Hansa,
erstmal frohe Weihnachten auch dir! Ich weiß zwar (auch schon gelesen) wie sehr du die Objektablage magst (hüstel pushst), aber ich hatte eigentlich den Thread etwas anders verstanden. Ging doch eher um ein erstes OOP-Programm, dass eine GUI bereitstellen soll, die dann (wahrscheinlich) zur Laufzeit einen Designer zur Verfügung stellt. Und wenn man nicht gerade eigene dfms parst, sollte die Objektablage hier wenig bringen. @mimi: Ok, merk schon die Idee von Interfaces ist nicht so leicht zu erklären. Also ein Interface ist wie eine eingeschränkte Klasse. Du kannst keine Variablen anlegen und auch keine Sichtbarkeit festlegen, nur Sichtbare Methoden. Ein Interface regelt sozusagen die Kommunikationsmöglichkeiten einer Klasse. Wenn dein Interface eine Methode draw enthält, heißt dass, das jede Klasse die dieses Interface implementiert Draw versteht. Aber was genau die Instanz macht, wenn ihr draw gesagt wird, geht aus ihrer Klasse und ihrem aktuellen Zustand hervor. Jede Instanz kann nur einer Klasse angehören, aber beliebig viele Interfaces haben, anders gesagt, jede Klasse kann beliebig viele Sprachen sprechen. Wenn du eine Klasse nimmst, die nur Methoden beinhaltet (und die sind alle public und abstract), dann hast du ein Interface (mehr oder weniger). Allerdings kannst du trotzdem nur von einer Klasse erben. Da hast du auch gleich das wichtigste an einem Interface, die Methoden sind alle abstrakt. In der Klasse musst du sagen, was genau in der Methode gemacht wird, im Interface kannst du das nicht festlegen. Für gemeinsame Eigenschaften solltest du dann eine abstrakte Klasse benutzen, diese kann dann die Methoden der Interfaces als abstract markieren. Aber auch hier musst du aufpassen, nicht jede Klasse hat z.B. eine Caption (ListBox mit Caption?). Zudem darf natürlich nicht jede Klasse Kinder haben (also untergeordnete Elemente). Bei einem Panel macht das Sinn, bei einem Label aber nicht, also musst du dort noch eine eigene Untergruppe machen. Z.B. wäre folgendes denkbar IZeichenbar, IKannKinderhaben. TBasisKlasse(IZeichenbar) -> TKannKinderhaben(TBasisKlasse, IKannKinderHaben) und daraus dann die einzelnen Klassen TBasisKlasse -> TDeinButton, TKannKinderhaben -> TDeinPanel, ... Für weitere Eigenschaften solltest du ruhig weitere Verfeinerungen festlegen. Musst halt immer gucken ob es Elemente gibt, die z.B. keine Farbe haben brauchen. Wenn alle Elemente eine Farbe haben sollen, trägst du die einfach in die Basisklasse ein und alle Nachfahren haben natürlich gleich eine Farbe. In jeder speziellen Klasse kannst du eine bereits vorhandene Methode (von irgendeinem Vorfahren) einfach überschreiben. Du schreibst nochmal die Methode in die Klassendeklaration und dahinter ein override. Wird eine Methode überschrieben, kannst du mit inherited <Methodenname> die Vorfahrfunktion aufrufen. Jede Klasse besitzt automatisch einen Konstruktor Create und einen Destruktor destroy (geerbt von TObject, jede Klasse erbt von TObject). In beide Methode gehört ein inherited create als erste Zeile (bzw. inherited destroy). Diese sorgen erst für das allozieren (oder freigeben) von Speicher durch Windows. |
Re: OOP Problem: änderungen werden nicht übernommen
@Hansa
Danke für dein versuch abr das geht leider am beitrag vorbei. Es geht hier im mein erstes richtiges OOP programm und in diesem zusammen hang um eine kleine GUI. Und das was du da gezeigt hast auf dem bild ist natürlch sehr einfach. @Der_Unwissende Also ein Button braucht eigetnlich auch keiner Kinder das brauchst nur das panel z.b.. Was hast du gegen meine idee mit den zwei variabeln ? Achso die sind dann natürlcih in jeder komponente, das ist ja klar. Aber die grund komponente soll ja auch schon was machen. bzw. aus deinen letzten beitrag kamm mir die idee das alle fenster objekte d.h. das Formula(r) die Panels und und und evlt. das die nur die eigenschaften haben sollten um komponenten zu verwahlten. Aber dann ist die Frage wie verwalte ich die Komponenten am besten im speicher so das ich leicht drauf zugreifen kann intern und extern ? In einen Interfaces werden also nur methoden defniert keine variabeln, ereignise eigenschaften ? und du kannst also bei jeder klassen deniation dieses Interface mit angeben ? Dann währe die frage was sollte da alles rein ? evtl. dies: Draw, add, del wobei add soll ja Create ausführen bei jedem "fenster" und del soll ja Destroy werden. Aber für mich ist im moment die verwaltung der Komponenten das größte problem. Wie soll ich dies am besten bewerkstilligen ? nagut die wirst warscheinlich keine 100 komponenten auf dein formular haben aber auch menupunkte z.b. beim mainmenu und Popupmenu und evlt. bei der Listbox wobei die listbox soll ja das erste menu werden sobalt die fertig ist wollte ich daraus ein Popupmenu basteln und ein Mainmenu. Habe ich shconmal gemacht aber leider ohne OOP.Und darum geht es mir ja hier. Das heißt ja das die fenster klassen einer vollkommen andre klasse her abgeleitet werden müsten also die normalen Komponenten wie z.b. einen button, label, Checkbutton und soweiter. Aber die verwaltung ist wie gesagt das größte problem. Du hast jetzt 20 komponenten in deinem Fenster und möchte das 3 ändern z.b. über Komoponente3.Color:=clred das währe ja der vorteil bei oop. wenn du alles in einer liste hättes müsste du ja ersteinmal den index raußfinden: Item[3].Color:=clred. das währe ja ein umdecken ervorderlich und genau das macht das ganze projekt so schwer. |
Re: OOP Problem: änderungen werden nicht übernommen
Ich seh schon, langsam nähern wir uns der OOP, aber es sind glaube ich noch ein paar Dinge nicht ganz klar. Heißt hier weder das du es nicht verstanden noch ich es schlecht erklärt habe oder so, sondern ein paar Dinge wurden (denke ich) einfach noch nicht gesagt und selbst dann ist die OOP schon etwas umfassender als das man mal ebend ein perfektes OO-Programm hinbekommt (falls das je der Fall ist).
Aber du befindest dich (imho) auf einem guten Weg. Eine wirklich wichtige Sache an der OOP ist es und die ist grundlegender als alle Anderen, zu abstrahieren. Ich glaube du betrachtest deine Probleme noch ein wenig zu konkret. Z.B. die Idee, dass bei einem Add ein Create aufgerufen werden muss, stimmt so nicht ganz. Du darfst dir immer nur einzelne Objekte anschauen, die kennen die Welt nicht sondern nur sich selbst. Sie kennen ihre Eigenschaften und können auf Kommunikation von Aussen reagieren, mehr nicht. Sie interessieren sich aber auch garnicht für die Welt. Dein Panel ist auch so ein Objekt. Es kennt erstmal nur die eigenen Eigenschaften. Sagen wir mal (da sind wir uns ja einig), eine Eigenschaft ist, dass ein Panel andere Objekte aufnehmen kann (sie verwalten kann). Das weiß das Panel, das ist auch gut so. Aber wo die anderen Objekte herkommen und was für Objekte auf der Welt leben, dass braucht das Panel doch gar nicht zu wissen, also weiß es das auch nicht. Dein eigentliches Programm ist wie gesagt die Welt. Da gibt es auch eine höhere Macht (den User), der die Welt beeinflusst und auf diese Beeinflussung reagiert deine Welt. Du definierst mit deinem Programmieren nur, wie sie worauf reagiert. Also quasi üblich wäre es für ein Panel, dass ein Panel folgendes kann:
Also könnte ein Panel folgende Form haben
Delphi-Quellcode:
Natürlich ist dies hier kein echter und vollständiger Code, aber von aussen gesehen sehe ich eigentlich doch nur, dass es ein draw, ein add und ein remove gibt. Es ist die Sache des TPanels was beim Aufruf gemacht wird. Sagen wir mal wir machen es etwas konkreter, wir kreieren eine Liste in Delphi (ohne Pointer, sondern mit Klassen). Ich denke es reicht sich hier auf das Add zu beschränken, daran kann ich schon alles zeigen was ich zeigen möchte (sollte es Namen schon in Delphi geben, ist dies nur Zufall und nichts aus der VCL)
type
TDeinPanel private // alle privaten Eigenschaften / Felder protected // setter und getter für diese Felder // alles zur eigenen Verwaltung public // Methoden die von anderen angesprochen werden können procedure draw; // damit es sich selbst aktualisiert procedure add(Obj); // fügt irgendein Objekt ein procedure remove(Obj); // löscht irgendeinobjekt end;
Delphi-Quellcode:
Ok, soweit sind mal die Deklarationen der Klassen fertig. Wie du siehst haben beide Klassen die Methode Add und beide müssen Add haben, da sie IObjectList implementieren. Von Aussen sehe ich nur dieses Add. Intern hat eine Klasse noch ein dyn. Array, die Andere eine TObjectList.
type
// Ein Interface, legt nur Methoden fest // die von aussen zugänglich sind IObjectList = Interface procedure Add(Obj : TObject); end; // erbt von TInterfaceObject, da Delphi Interfaces 3 Standard-Methoden haben // die ich hier nur nicht implementieren möchte // Und diese Klasse implementiert IObjectList (hat also alle Methoden des Interfaces) TObjectList_Array = class(TInterfacedObject, IObjectList) private Objects : Array of TObject; public procedure Add(Obj : TObject); // muss hier rein, da IObjectList implementiert wird! end; TObjectList_List = class(TInterfacedObject, IObjectList) private Objects : TObjectList; public procedure Add(Obj : TObject); // muss hier rein, da IObjectList implementiert wird! end; Schauen wir uns nun das Add an.
Delphi-Quellcode:
Wie du siehst machen beide nicht das gleiche. Eine Methode speichert das übergebene Obj in ein Array, das andere in eine Liste. Wenn du aber davon abstrahierst, würdest du sagen, beide speichern Obj. Gut, hier fehlen jetzt Methoden um ein Element auch wieder raus zu holen, aber denk dir die einfach. Auch diese sähen für ein Array anders aus als für eine Liste, aber beide würden dir ein Element rausholen.
procedure TObjectList_Array.Add(Obj : TObject);
begin setLength(self.Objects, length(self.Objects) + 1); self.Objects[length(self.Objects) - 1] := Obj; end; procedure TObjectList_List.Add(Obj : TObject); begin self.Objects.Add(Obj); end; Und dieses Abstraktere siehst du nur von aussen. Wenn du jetzt eine Variable vom Typ IObjectList hast, dann weißt du, dass Add ein TObject aufnehmen kann. Wie das intern gespeichert wird weißt du nicht, aber musst du auch nicht. Es handelt sich dabei um das so genannte Black-Box-Prinzip. Du hast eine schwarze Kiste. Die kannst du nicht öffnen, du weißt was du reinwerfen kannst und du weißt was rauskommt. Mehr nicht, aber das reicht dir. Und auch das nochmal als Programm:
Delphi-Quellcode:
Schau dir den Code mal gut an. Wie du siehst, kannst du Variablen vom Typ IObjectList übergeben. Die beiden TObjectList_xxx haben dieses Interface implementiert. AddToList weiß zu keinem Zeitpunkt ob Liste gerade eine TObjectList_Array oder TObjectList_List bekommen hat. Es weiß nur, dass es eine Methode Add gibt und die wird aufgerufen.
// Fügt Element in die Liste ein
procedure AddToList(Liste : IObjectList; Element : TObject); begin // klappt, da jedes IObjectList eine Methode Add hat, der man ein TObject geben kann Liste.Add(Element); end; procedure Test; var L1 : TObjectList_Array; L2 : TObjectList_List; begin L1 := TObjectList_Array.Create; L2 := TObjectList_List.Create; AddToList(L1, TObject.Create); AddToList(L2, TObject.Create); end; Soweit klar? Hier bitte wirklich an diesem Beispiel nachfragen wenn etwas unklar ist! Also alles was geerbt wurde (irgendwann auf dem Weg von TObject -> TIrgendwas) bleibt erhalten. Das heißt wenn du ein Objekt T1 von TObject erben lässt, kannst du es auch überall dort verwenden wo ein TObject verlangt wird. Dann kannst du ein T2 ableiten (TObject -> T1 -> T2) und T2 kannst du überall dort benutzen wo ein TObject oder T1 gebraucht wird. Dann kannst du ein T3 ableiten... Wichtig ist, dass du immer nur die Eigenschaften hast, die der Typ (variable : TIrgendwas) festlegt.
Delphi-Quellcode:
So, interessant ist natürlich der Letzte Fall. Du übergibst ein T2, dass die Eigenschaft Count hat. Aber die Methode resetCount2 erwartet ein T1. Also werder von inst2 nur die Eigenschaften genommen, die auch ein T1 hat, count gehört nicht dazu. In der Methode siehst du also auch wirklich nur das, was der Variablentyp (T1) beschreibt.
type
T1 = class(TObject) public color : TColor; end; T2 = class(T1) public count : Integer; end; procedure setColor(t : T1); begin t.Color := clRed; end; procedure resetCount(t : T2); begin t.Count := 0; end; procedure resetCount2(t : T1); begin t.Count := 0; end; procedure Test; var inst1 : T1; inst2 : T2; begin inst1 := T1.Create; inst2 := T2.Create; setColor(inst1); // klappt super setColor(inst2); // klappt auch resetCount(inst1); // geht nicht, da inst1 nicht vom Typ T2 resetCount(inst2); // klappt super resetCount2(inst2); // klappt nicht end; Ok, hoffe das war soweit verständlich. Was dein Problem mit der Verwaltung angeht, so sollte es eigentlich recht nahe an dem Beispiel der Listen dran sein. Modellier (am besten einfach auf Papier oder so) erstmal die Beziehung der Objekte untereinander. Also wer hat welche Eigenschaften. Das macht vieles einfacher. Ich denke du würdest erstmal mit den zwei Interfaces auskommen, die ich schon genannt hatte. Wie sie funktionieren (also wie verwaltet wird) kannst du dir später überlegen, erstmal musst du dir überlegen was du alles brauchst. Ein häufiger Fehler (hab ihn sehr sehr häufig gemacht) ist es, einfach los zu legen. Dann kommt irgendwann der Punkt wo einem klar wird, man hat etwas vergessen und man kann mehr oder weniger von Vorne anfangen (macht sich immer schlecht, ist immer teurer als erwartet und lässt sich fast immer vermeiden). Deshalb modellier erstmal im Kopf / auf Papier in Ruhe durch. Der Hauptvorteil der OOP ist, dass du dir über die Details zu keinem Zeitpunkt Gedanken machen musst (ganz übertrieben gesagt). Wenn du in deiner schwarzen Kiste die Objekte statt in einem Array in einer TObjectList speicherst, dann ist das dem Programm egal. Es wird halt intern anders gespeichert, aber du wirfst noch das gleiche rein und bekommst noch das gleiche raus. Hier liegt dann auch der Vorteil von Interfaces. Wenn du als Argument nur ein IObjectList eingetragen hast, ist es dem Programm egal ob die Instanz nun ein TObjectList_Array, eine TObjectList_List oder gar eine TObjectList_FibonacciHalde ist. Die Methode Add gibt es, das reicht. Und nochmal konkret auf deinen Fall bezogen, ja es ist schon richtig, du trägst in die Interfaces ein Add und Remove (und was auch immer dazu gehört) ein. Hier musst du nur drauf achten, dass jedes Interface genau das beinhaltet, was zusammen gehört. Ein Interface mit nur Add macht keinen Sinn (siehe oben ;-)), aber genauso wenig macht ein Interface mit nur einem Remove Sinn. Eines das Hinzufügen und Entfernen kann, ist hingegen schon geeigneter, oder? Und so kannst du weiter machen, erstmal die Grundlegenden Eigenschaften in Interfaces (also nur in Hinblick darauf, dass es irgendwann mal irgendein Objekt geben wird, dass diese Methoden braucht). Dann geht es mit abstrakten Klassen weiter. Hier kommen dann Methoden, Ereignisse und Variablen rein, die spätere konkrete Klassen gemeinsam haben (z.B. wird alles was Sichtbar ist auch eine Position haben, ...). Aber auch hier nur dass was auch zusammen gehört. Wir hatten ja schon, dass nicht jedes Objekt mal einen Titel (Caption) haben muss (aber die einen haben kann man wieder von einer gemeinsamen Klasse ableiten). Das alles sind natürlich nur Tipps, ich würde sagen es ist immer einer guter Weg so an ein Problem ran zu gehen. Du bleibst flexibel. Es ist gerade bei am Anfang kleineren Projekten schon ein gewisser Mehraufwand hinter und man fragt sich immer mal lohnt sich das? Aber ehrlich, wenn du später was neues einfügst und gut modelliert wurde, ein Traum! Und wenn du mal Code umschmeißen musst, weil nicht gut modelliert wurde... (und das umschmeißen kostet deutlich mehr Zeit/Geld als das bisschen mehr Planung am Anfang). Falls du dich für die Modellierung entscheidest, würde ich die gerne sehen, dann kann ich dir da sicher weiterhelfen (falls ich dir bisher helfen konnte :wink:) Lass ruhig Dinge bei denen du dir unsicher bist noch etwas aussen vor (wäre hier eigentlich nur das Hauptformular) oder bau es so ein wie du denkst. Muss auch nicht vollständig sein, geht ja nur ums Prinzip. Und denk noch nicht zu sehr über alle speziellen Eigenschaften und Beziehungen nach. Was man später in ein oder zwei Variablen, mit Listen oder ohne, ... macht ist für die schwarze Kiste erstmal egal. Die guckt man sich später immer schön einzeln an und dann hat man schon den Vorteil dass man weiß was reinkommt und was rauskommt. Ach ja, wie du später an ein bestimmtes Objekt kommst, ist viel leichter als du vielleicht gerade glaubst, aber ich habe es erstmal aussen vor gelassen, da wie gesagt die Modellierung vorher dran kommen sollte und du nie über Dinge nachdenken brauchst (in der OOP) die noch nicht aktuell sind. Du kannst schließlich sehr sehr leicht erweitern! Gruß |
Re: OOP Problem: änderungen werden nicht übernommen
Modellierung damit meinst du die Klassenstrucktur aufbauen also wie die grundklasse ausehen soll.
Aber ich glaube ich habe verstanden worauf du hinnaus wolltes: Die objekte arbeiten für sich alleine. Das interface hat nur public funktionen/proceduren die in jeder abgeleitetn klassen zu sehen sind hier noch mal eine frage: Können die Klassen die nicht abgeleitet werden die proceduren/funktionen aus dem Interface sehen ? oder können "nur" abgeleitet klassen diese proceduren/funktionen sehen ? was mich überrascht hat war das du
Delphi-Quellcode:
ein Create in einer Procedure aufruftst. das war irgenwie neu für mich.
procedure Test;
var L1 : TObjectList_Array; L2 : TObjectList_List; begin L1 := TObjectList_Array.Create; L2 := TObjectList_List.Create; AddToList(L1, TObject.Create); AddToList(L2, TObject.Create); end; aber ich denke ich entscheide mich für das Modellieren von Klassen. also was alle Komponenten auf jedenfall gemeinsamm haben währen bei einer GUI z.b.: - add, del, draw, repaint - onDraw, onAdd, onDel, onrepaint wobei auch Mausereignise könnten ja auch noch jede komponente habe würde ich mal sagen oder ? wie z.b.: onMouseDown OnMouseMove onMouseUp OnMouseLave(wenn du mit der Maus die komponenten verlässt) wobei die tastertur ereignise nicht umebdingt jede komponete haben sollte. z.b. ein Panel braucht keine Taster ereignise aber ein TEdit. aber was ich an dieser sache immer noch nicht verstehe ist warum das verwalen erst zum schluss kommt. angenommen du hast jetzt ein paar komponenten geschrieben und die sind soweit fertig. du kannst von jeder dieser komponenten ein instanz erzeugen und benutzten. aber wenn du mehre benutzen möchte musst du die ja auch verwalten z.b. alle zeichnen(evlt. nur die die geändert wurden), bestimmte komponenten löschen oder hinzufügen. evlt. möchtes du von einer einen caption ändern oder so. Was ich auch nicht verstehe ist warum bei den standart komponenten von delphi der Panel ein Caption hat. den braucht er doch garnicht. Alle komponenten haben die methoden von dem inteface, aber sie brauchen ja auch noch eigene z.b. ein Memo braucht scollbalken wobei ein Edit keine braucht.(währe auch nicht schlecht). Wenn ich dein Beitrag verstanden habe geht es darum ersteinmal alle komponenten die ich brauche zu enfernen von standart obj dann TEdit, TLabel, TButton, ..... habe ich entwurfen. dann muss ich mir gedanken machen wie ich sie verwalte, sehe ich das so richtig ? z.b.
Delphi-Quellcode:
das währe mein Grundobjekt(ersteinmal ohne interface da ich den sinn noch nicht so ganz verstehe)
TStdObj = class
private FName, FCaption, FTitel:String; Fx,Fy,Fw,Fh,Ftag:Integer; fbgColor, fvorColor:TColor public published property Caption; read FCaption; write FCaption property name;read fName; write fName property Titel;read fTitel; write fTitel end; von dieser Klasse leitet ich nun die TEdit komponente aber TEdit braucht ja kein Caption sondern Text wo man ein Text eingeben kann weil Caption soll ja nur als anzeige dinnen. muss ich jetzt für jeden fall eine weite grund komponente schreiben oder kann ich den Caption verstecken und durch Text ersetzten. mir geht es ja ersteinaml nur darum eine Klassenstrucktur zu finden die Optimal für eine GUI währe und dann um dann die mit Leben zu füllen. Ich würde schon sagen das du mir weiter Hilfe auf die einer oder andre art und weise. z.b. bei jedem beitrag wird mir was Klarer *G*. z.b. bei deinem letzten: das mit der Schwartzen kiste das ich z.b. mehre komponenten geschrieben habe und diese alle das "gleiche" create haben und somit das gleiche Create von der grundklasse aufgerufen wird wobei hat dies eigetnlich vorteile ? weil wenn ich in der Grundkomponete ein Item defniere wird es ja überalle die item geben. PS: ich muss leider um ca 18 Uhr wieder nach Hause und da habe ich kein internet. währe schön wenn wir uns nochmal im IRC treffen könnten oder so weil ICQ habe ich nicht. |
Re: OOP Problem: änderungen werden nicht übernommen
Liste der Anhänge anzeigen (Anzahl: 1)
Kein Thema, hab auch kein ICQ (und auch nicht vor in nächster Zeit etwas daran zu ändern). In welchem Channel finde ich dich denn?
Zitat:
Wenn du sagen wir einen BaseButton, einen Button, einen SpeedButton hast, wobei dies auch die Spezialisierung ist (BaseButton -> Button -> SpeedButton), dann kannst du nicht mit dem SpeedButton anfangen. Du könntest dort zwar alles Eigenschaften des SpeedButton reinschreiben, aber die von einem Button hat ein Speedbutton schließlich auch. Würdest du mit dem SpeedButton anfangen, könntest du dort alle Eigenschaften reinschreiben, die die auch ein Button hat wieder löschen und den Button entwerfen, hier dann die entfernen, die auch ein BaseButton hat... Schöner ist mit dem kleinsten gemeinsamen anzufangen. Das kannst du dann in kleinen Schritten erweitern. Wenn dein BaseButton erstmal nur ein Rechteck ist, ist das super. Ein Rechteck lässt sich leicht implementieren. Ist das fertig, kommt vielleicht ein Text in den BaseButton, wieder nur ein kleiner Schritt. Kleine Schritte bedeuten weniger Fehler. Wenn du erst alle Eigenschaften festlegst und TopDown arbeitest, erschlägt dich das bei einem Speedbutton. Es gäbe soviel zu tun, dass du nicht weißt wo du anfangen solltest (aber du kannst es machen). Ähnlich ist es mit der Modellierung. Bevor du etwas verwalten kannst, muss etwas zum verwalten existieren. Deshalb fängst du mit etwas ganz einfachem an, was eigentlich nichts braucht (ausser dem Delphi gegegebenen). Basiert etwas auf dieser Klasse, ist das kein Problem, die Klasse hast du dann ja schon fertig. Wenn du alle Lebewesen der Welt kennst, kannst du leicht eine Welt erschaffen, auf der sie alle Leben können, du weißt ja schon was für Lebewesen existieren. Würdest du sonst eine Welt schaffen, die Wasser hat (weil du Fische planst), dann würdest du in Ruhe die Fische entwerfen, dann die Wale, dann die Ameisen, OH, Moment, Ameisen brauchen Land. Ok, kein Thema du schaffst auch noch Land. Dann schaffst du die Affen, Mensch, jetzt brauchst du auch noch Bananen und Bäume, ... Verstehst du was ich meine? Du kannst auch mit der Verwaltung anfangen, aber es wäre schwerer im Nachhinein anzupassen. An sich kannst du auch eine Verwaltung planen, aber nicht konkret. Bleib da einfach flexibel. Merk dir nur, dass es eine Art zu speichern gibt, nicht mehr. Du weißt man speichert indem man etwas hinzufügt, etwas entfernt und sich mal anguckt was es schon gibt. Das ist alles. Wie man genau hinzufügt oder entfernt ist doch erst wichtig wenn du wirklich speichern möchtest. Ich häng dir mal ein sehr einfaches UML-Diagramm an. Weiß nicht ob du mal damit gearbeitet hast, die sind glaube ich nur Teilweise intuitiv. Es soll dir einfach nur die Modelierung erklären. Die Pfeile würden die meisten Menschen immer in umgekehrter Richtung setzen wollen. Zur Erklärung, sie heißen Verallgemeinerung (man könnte sie so auffassen). Du zeigst immer auf eine Verallgemeinerung. Also würde ein Schimpanse auf Affe Zeigen, Affe auf Säugetier, Säugetier auf Tier, ... Interfaces sind Schnittstellen, die +, - und # Zeichen stehen nur für public, private und protected. Hoffe es hilft dir überhaupt. Wäre nur eine Möglichkeit es zu modelieren. Wichtig ist, es gibt immer viele Arten der Modellierung, aber es ist nicht nur eine richtig! Verwende immer (auch beim Diagramm) den Grundsatz für alle Probleme der Informatik : Teile und Herrsche. Schau dir nicht alles auf einmal an, sondern wirklich in kleinen Stücken, dass macht es leichter. Ich versuch dir mal hier das Diagramm zu erklären. Es ist wie gesagt nicht vollständig. Fang am Besten oben Links an, da hast du das Interface Drawable (Zeichenbar). Es hat eine Funktion Draw, dass war's auch schon. Nun nimm den Pfeil mit der gestrichelten Linie, der auf dieses Interface zeigt und folge ihm. Er kommt von TVisibleBaseClass. Die Klasse ist in zwei Teile geteilt. In der oberen Hälfte stehen die Variablen, das Minuszeichen heißt dass sie alle private sind. In der unteren Hälfte stehen die Funktionen. Ein plus heißt sie sind public, eine # protected. Was für Felder es hier gibt und was für Methoden ist eigentlich erstmal egal, sollte nur grob was zeigen. Wichtiger ist der Pfeil. Du zeigst auf eine Generalisierung oder anders gesagt, TVisibleBaseClass ist ein spezielles IDrawable (es kann alles was IDrawable kann und mehr). Hier heißt dass, das jede TVisibleBaseClass immer ein Draw beherrscht. Das macht natürlich nur Sinn, wenn auch jedes Sichtbare Element von dieser Klasse erbt (dafür musst du dann halt sorgen). Schau dir nun die anderen beiden Schnittstellen an (ohne die Pfeile). Es sind die zwei weiteren obersten Kästchen, IContainer und IContainable. Fangen wir mit letzterer an. IConainable ist leer. Das ist auch beabsichtigt. IContainable sollen einfach alle Elemente werden, die abgelegt werden können. Warum dieses Interface? Ganz einfach, auch deine GUI wird viele Eigenschaften der Sichtbaren Elemente haben. Sie muss auch gezeichnet werden, hat auch Position und Breite sowie Höhe, ... Aber auf ein Panel wirst du sicherlich keine Form legen wollen, oder? Ich würde es jetzt so wie in Delphi machen und nein sagen. Deshalb muss es eine Eigenschaft geben, die eine GUI eben nicht hat. Dies ist durch das Interface gegeben. Folge dem gestrichelten Pfeil von IContainable zur TContainableBaseClass. Es heißt, dass jede TContainableBaseClass auch Containable ist. Von dieser Klasse (die keine eigenen Methoden braucht) geht ein Pfeil nach oben zur TVisibleBaseClass. Dieser durchgezogene Pfeil heißt, TContainableBaseClass erbt von TVisibleBaseClass. Alles was also in TVisibleBaseClass steht, hat TContainableBaseClass auch. Beachte nur kurz, dass das Kästchen TGui keinen Pfeil zu TContainableBaseClass hat und keinen zum Interface Containable. Damit fehlt TGUI also diese Eigenschaft. Ok, zurück nach oben zum Interface in der Mitte. IContainer ist das Interface, dass alle Objekte implementieren sollen, wenn sie andere aufnehmen/verwalten können. Was braucht man um verwalten zu können? Na ja, eine Möglichkeit etwas hinzu zu fügen, etwas zu entfernen und natürlich die Möglichkeit aufs Gespeicherte zu zu greifen. Es muss nicht so aussehen wie hier! Die Möglichkeiten könnte man (sollte man) deutlich flexibler wählen. Zwischen IContainer und IContainable gibt es eine Linie mit einem Karo dran. Da steht auch noch ein 1 * dran. Ist das Karo wie hier innen weiß, so nennt man das eine Aggregation. Das bedeutet soviel wie : IContainer besteht unter anderem aus Elementen vom Typ IContainable. Ist hier eigentlich falsch, da nur Klassen Elemente aufnehmen können, wollte aber nicht noch extra eine Klasse zwischen setzen. Die 1 * heißt, dass 1 IContainer beliebig viele (auch 0) IContainable aufnehmen kann. Das wäre die oberste Zeile, die drei Interfaces. Schau dir nun die beiden gestrichelten Linien die von IContainer weggehen an. Sie gehen zu TGui und TVisiblePanel. Anders gesagt, alle Objekte die später andere Aufnehmen können müssen das Interface IContainer implementieren (es gilt auch umgekehrt, alles was IContainer implementiert kann später Objekte aufnehmen). Es ist auch schon festgelegt was für Objekte, es müssen welche vom Typ IContainable sein. Nun bleiben eigentlich nur noch die Pfeile die von TContainableBaseClass weggehen übrig. Diese kommen von TVisibleButton und TVisiblePanel. Wie du siehst, sind diese Elemente damit vom Typ IContainable (erben sie von TContainableBaseClass) und vom Typ TVisibleBaseClass (auf gleiche Weise geerbt), TGui erbt nur von TVisibleBaseClass. Ein TVisiblePanel kann zu dem als Container dienen, die TGui auch, ein TVisibleButton hingegen nicht. Ihm fehlt eine Beziehung zu IContainer. Ich weiß nicht, ob das jetzt wirklich anschaulicher ist oder nicht, aber das ist der Gedanke den du vervollständingen müsstest. Es ist noch überhaupt nicht festgelegt, ob ein Button später ein Rechteck, ein Dreieck oder ein Kreis ist. Aber es ist im Moment noch nicht wichtig. Auch die Verwaltung ist hier schon geplant, aber eben noch nicht konkret. So modellierst du erstmal so weit wie es dir möglich ist (es sollte halt ein einfaches Modell bleiben). Man kann sich natürlich auch tot modellieren, aber du hattest ja eine Vorstellung, was du für den Anfang haben möchtest, wie gesagt Erweitern ist sicher nicht das Problem. Wenn du dass erstmal modelliert hast, dann geht es erst an die Implementierung und auch dort jede Klasse für sich. Wenn du dann etwas implementierst, brauchst du nur dein Modell umzusetzen, das überlegen über mögliche Abhängigkeiten und sowas wie, wie kann die Gui Elemente aufnehmen, die erst noch geschrieben werden entfällt. Würdest du jetzt ein TVisibleMemo schreiben, musst du nur gucken wovon es erbt und es könnte ohne Änderung der Gui von dieser oder einem Panel verwaltet werden (wenn es ein IContainer ist). Damit kannst du die Implementierung sehr viel einfacher durchführen. Die ist dann aber eine andere Sache. Dort fängst du dann übribens immer mit den Klassen / Interface an, auf die nur gezeigt wird. Die anderen besitzen eine Abhänigkeit von diesen Klassen/Interfaces (kann nur von Dingen die es gibt erben). Gruß Der Unwissende |
Re: OOP Problem: änderungen werden nicht übernommen
Das stimmt, es ist einfacher wenn ich von vorrein weiß wie die objekte aussehen und welche ich haben. um sie zu verwalten. Von UML habe ich schon mal gehört aber noch nicht mit gearbeitet.
Aber aus deinen diagramm leitet ich folgendes ab: alle komponenten sind von IContainer abgeleitet. Alle komponenten die sichtbar sein soll werden von TVisibleBaseClass abgeleitet der button scheint von TContainableBaseClass abgeleitet zu sein. d.h. es muss dann noch eine zweite TVisibleBaseClass gebebn die dann z.b. andre funktionen bereit stellt wie z.b. gruppenbarsit. die einen brauchen diese klassen die anderen wiederum diese und soweiter. ich habe mir meine gui in entwar so vorgestellt: das fenster soll ein einfaches Rechteck sein wo oben eine line gezeichnet wird als titel so ca 10(y) pixel unter dem anfang vom Rechteck. das soll der header sein, der jeder kompoenten haben sollte. genauso wie die Scrollbalken das sind alles weiter komponenten die überalle eingesetzt werden sollen. Der Buttonsoll ersteinmal ein rechteck sein mit einen Text drin mehr nicht.später soll der erweiter werden. Schritweise vorzugehen ist warscheinlich das besten. D.H. Wie sollen die 3 ersten komponenten aussehn. Was du mit deiner Welt beschrieben hast meine ich jetzt. Das ich erst die komponenten erstelle und dann versuche sie zu verwalten. gut. was haben ein Button, ein Label, ein fenster gemeinsamm und was nicht ? zum Zeichnen eine procedure zum Löschen der Komponente eine procedure zum updaten eine Komponenten variabeln z.b. Name, Caption, x,y,w,h,tag, taborder,visible,Autosize,Image,Form(z.b. rund, eckig) TMyStyl(für das aussehen der komponente, z.b hintergrund/vordergrund farbe, schriftart, bitmapfont und soweiter) wobei das fenster noch VisibleScollbalken, VisibleTitel haben sollte aber wie sollte das am besten defniniert werden ?
Delphi-Quellcode:
und bei der zweiten klasse sollte statt caption dann text stehen. nur wie speicher ich dann sowas. Währe hier ein interface praktisch ? von den beide klassen abgeleitet werden ? oder soll caption und text ersteinaml in andren klassen defniert werden ?
tStdObj1 = class
private fCaption, fName:String fx,fy,fw,fh,ftag,ftaborder:Integer; public; property Caption property name property x property y property w property h property Tag property Taborder end; |
Re: OOP Problem: änderungen werden nicht übernommen
Liste der Anhänge anzeigen (Anzahl: 1)
Seid ihr immer noch an der Theorie dran ? Aber mein Beispiel war echt zu einfach. Folgendes hat mir nicht gepaßt : die Form war zu klein, die Farbe der gelben Form zu ätzend. :mrgreen: Für die Nachfahr-Forms soll außerdem ein Panel eingeführt werden. Und weils so schön ist soll das gleich abgerundete Ecken haben. Außerdem sollen die vorhandenen Controls nach rechts. Das geht so :
Delphi-Quellcode:
Jo, die Farbe des Panels wurde noch geändert und der ButtonClick hat jetzt auch eine Funktion. Die GrundForm3 wird übrigens in Unit1 so aufgerufen :
unit Unit3;
interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, Unit2, ExtCtrls, StdCtrls, Grids; type TGrundForm3 = class(TGrundForm2) Panel1: TPanel; procedure FormCreate(Sender: TObject); procedure Button1Click(Sender: TObject); private { Private-Deklarationen } public { Public-Deklarationen } end; var GrundForm3: TGrundForm3; implementation {$R *.dfm} procedure TGrundForm3.FormCreate(Sender: TObject); // (C) swissdelphicenter bzw. Beitragsschreiber const bgcolor = $00FFDDEE; linecolor = $00554366; var img: array of TImage; reg: hrgn; i: Integer; begin inherited; for i := 0 to ComponentCount - 1 do begin if Components[i].ClassName = 'TPanel' then begin setlength(img, Length(img) + 1); img[i] := TImage.Create(Self); img[i].Width := (Components[i] as TPanel).Width; img[i].Height := (Components[i] as TPanel).Height; img[i].Parent := (Components[i] as TPanel); img[i].Canvas.Brush.Color := clSkyBlue; // Änderung !! img[i].Canvas.pen.Color := bgcolor; img[i].Canvas.Rectangle(0,0,img[i].Width, img[i].Height); img[i].Canvas.pen.Color := linecolor; img[i].Canvas.RoundRect(0,0,img[i].Width - 1,img[i].Height - 1,20,20); reg := CreateRoundRectRgn(0,0,(Components[i] as TPanel).Width, (Components[i] as TPanel).Height, 20,20); setwindowrgn((Components[i] as TPanel).Handle, reg, True); deleteobject(reg); end; end; end; procedure TGrundForm3.Button1Click(Sender: TObject); begin inherited; showmessage ('blubb'); end; end.
Delphi-Quellcode:
Wenn auch die Theorie hier Vorfahrt zu haben scheint, es gibt auch Mitleser ! Und das Ergebnis : siehe Anhang.
implementation
uses Unit3; {$R *.dfm} procedure TGrundForm.Button1Click(Sender: TObject); begin GrundForm3.Show; end; |
Re: OOP Problem: änderungen werden nicht übernommen
ist das jetzt eine eigene GUI oder benutzt du delphi komponenten ?
Ich möchte nämlich eine komplet eigene GUI entwickeln die dann in Spielen z.b. verwendet werden können. ich möchte diese GUI mit OOP entwickeln da gibt es nur einige probleme mit der Klassenstrucktur. Wir haben zwar schon ausfürhlich darüber geredet aber ich weiß immer noch nicht wie z.b. das Grundobjekt ausehen sollte. von denn alle Komponenten abgeleitet werden sollen. z.b. dachte ich jetzt das das grundobjekt nur paar variablen/eigenschaften/methoden haben sollte. Mehr nicht. wie z.b. name, Caption, X,Y,W,H,Visible,onMouseMove,OnMouseDown, OnMouseUp. die ereignise zu schreiben ist kein problem und das aber was ein problem ist eine optimale klassenstrucktur zu entwickeln. |
Re: OOP Problem: änderungen werden nicht übernommen
Zuerst mal : Prost Neujahr ! :mrgreen:
Zitat:
|
Re: OOP Problem: änderungen werden nicht übernommen
Ja ein Frohers neues Jahr.
Ich meinte eine eigene keine die von Delphi verwendet wird. Ein komplet eigne mit eigenen funktionen/proceduren und soweiter. die ohne die VCL auskommt. Ich möchte nicht alles per TImage regeln sondern über eine eigene GUI regeln. die dann alle komponenten selbst zeichne wie z.b. ein Fenster, ein Button, ein Label und soweiter. ich möchte NICH auf TFrom, TButton, TLabel zurückgreifen. |
Re: OOP Problem: änderungen werden nicht übernommen
Frohes Neues euch Beiden! (und allen anderen)
Ja, damit scheidet Hansa's Lösung wohl aus. Aber willst du komplett auf Delphi Komponenten verzichten oder nur auf Controlls (also die Sichtbaren Dinge). Also wenn du jetzt (noch?) eine TObjectList verwendest, dann wäre das ja auch schon eine Delphi Komponente, da würde ich dann aber über den Sinn des Ersetzens nachdenken. Jedenfalls ist es auch kein Problem eine GUI mit Delphi Komponenten zu schreiben und diese dann später durch eigene Implementierungen zu ersetzen. Das Zauberwort heißt (überraschender Weise) mal wieder Interfaces. Ich weiß, die Idee von den Dingern ist noch nicht so wirklich klar (oder?). Also gehen wir mal ein sehr schönes praktisches Beispiel an, du möchtest Plugins ermöglichen. Die Motivation hinter Plugins ist natürlich allen klar, aber trotzdem noch einmal grob zusammen gefasst: Plugins ermöglichen es, ein Programm mit weiteren Funktionen auszustatten. Zum Zeitpunkt der Programmerstellung ist dabei noch nicht klar, was für Plugins es geben wird. Der Sinn ist es gerade beliebige Funktionen (nahezu) in ein Programm aufnehmen zu können. Ok, jetzt muss also das Programm mit etwas umgehen können, dass noch gar nicht existiert. Wie also kann man das eigene Programm darauf vorbereiten mit unbekanntem umzugehen. Man könnte natürlich mit Neuronalen Netzen arbeiten und das Programm lernen lassen und irgendwann (hoffentlich) versteht es dann jedes Plugin, dass kommt, ist aber nicht grade trivial und eigentlich hätte man doch gerne, dass schon das erste Plugin funktioniert. Muss man also einen anderen Weg gehen. Da man wie gesagt noch nicht weiß was genau kommt, geht man in gewisser Weise den anderen Weg. Man stellt alle (öffentlichen) Daten einem Plugin zur Verfügung. Dieses muss die dann über eine festgelegte Schnittstelle holen und zurück geben (also die Daten). Ganz wichtig ist natürlich noch, das Plugin muss sich bekannt machen können (Registrieren/Deregistrieren), da dass Programm ja sonst nichts vom Plugin weiß. Definierte Schnittstelle, hm, die nahezu sinngemässe deutsche Übersetzung von Interface (Zwischengesicht tut es auch). Ein Interface macht nichts anderes, als solche Schnittstellen fest zu legen. Da alle Methoden eines Interface nach aussen Sichtbar sind, kann ein Plugin über diese Methoden auf ein Programm zugreifen. Benutzt das Plugin als Schnittstelle ein Interface, wird es nie mehr können als eben genau diese Schnittstellen zu benutzen (das Programm kennt nicht direkt das Plugin und das Plugin kennt nicht direkt das Programm). Beide kennen nur das Interface. Das ist auch gut so, wenn jmd. ein Plugin für den InternetExplorer schreiben wollen würde und der müsste erst die mind. 4 mio. Zeilen durchgehen (letzter Stand den ich kenne), nun ja... Ok, was hat das jetzt mit der GUI zu tun? Schauen wir uns doch mal eine beliebige GUI an, warum nicht Delphi. Delphi ist erstmal eine GUI, ok, das ist gut. Delphi hat Komponenten und was noch ganz toll ist, man kann sogar welche nachrüsten. Viele davon stammen nicht aus dem Hause Borland, es spricht also einiges dafür, dass die Erzeuger nicht den Source von Delphi kennen. Und trotzdem funktionieren (die meisten) Komponenten wie sie sollen. Warum? Nun ja, Delphi macht natürlich nichts anderes als ein Interface zur Verfügung zu stellen. Es ist natürlich etwas komplexer als ein in Delphi geschriebenes Interface (immerhin gehört der Programmcode ja mit zu dem was Delphi verstehen muss), aber es ist an sich auch nur ein Interface. Wichtig ist, wenn ein Komponente benutzbar sein soll, muss diese über eine festgelegte Methode registriert werden und ebenso wird eine Komponente über ein festgelegte Methode entfernt. Dabei ist halt nur der Name der Methode sowie die Parameter bekannt. Man weiß natürlich auch was die Methode leistet, aber es interessiert einen i.d.R. nicht, was intern gemacht wird. Deshalb benutzt man hier ein Interface. Wenn Delphi Komponenten nun anders in 2005 registriert als in 7, dann störrt einen das nicht (sehr idealisierte Vorstellung, die durch Änderungen an Interfaces zu nichte gemacht wird). Genauso ist es mit deiner GUI, legst du nur die Schnittstellen fest, kannst du die GUI beliebig erweitern. Es muss halt nur eine Möglichkeit geben, neues bekannt zu machen. Würdest du ein Delphi-Form benutzen, was zusätlich ein MainForm-Interface implementiert, dann könntest du dies auch später durch eine beliebige andere Implementierung des MainForm-Interfaces ersetzen. Du abstrahierst also wieder einfach vom Konkreten (deshalb solltest du dir immer noch über die Beziehung der einzelnen Interfaces Gedanken machen). Gruß Der Unwissende |
Re: OOP Problem: änderungen werden nicht übernommen
Zitat:
|
Re: OOP Problem: änderungen werden nicht übernommen
Zitat:
Nur um ein Fenster auf das erstmal ein Label und ein Button gesetzt werden kann (keine vollwertige GUI, nur ein erster Schritt |
Alle Zeitangaben in WEZ +1. Es ist jetzt 00:40 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