|
Antwort |
Registriert seit: 1. Dez 2002 Ort: Oldenburg(Oldenburg) 2.008 Beiträge FreePascal / Lazarus |
#1
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: test:=test3 jetzt wird ja test mit test3 verküpft und so dachte ich mir das in meinem problem auch. 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.
Michael Springwald
MFG Michael Springwald, Bitte nur Deutsche Links angeben Danke (benutzte überwiegend Lazarus) |
Zitat |
Registriert seit: 12. Jun 2002 3.483 Beiträge Delphi 10.1 Berlin Professional |
#2
Dazu rate ich dir mal ein OOP Tutorial durchzulesen. Dann wirst du sehen, dass z.B. die Draw-Methode am besten virtuell sein sollte, und was man unter Information-Hiding versteht. Feld-Deklarationen haben nichts im public-Bereich zu suchen, sondern gehören in den private-Bereich. Im protected unt public-Bereich wird dann per Eigenschaften (=> property) der Zugriff geregelt. So kann man z.B. mit "property Caption: string read FCaption write SetCaption;" auf die Veränderung der Caption mit einem Neuzeichnen reagieren, was mit deinem aktuellen Programmcode nicht geht.
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
Andreas aka AHUser aka jbg
Mein Blog - kombiniert mit all meinen Delphi Tools |
Zitat |
Registriert seit: 1. Dez 2002 Ort: Oldenburg(Oldenburg) 2.008 Beiträge FreePascal / Lazarus |
#3
Vielen Dank. Das tutor werde ich mir gleich mal durchlesen. evlt. gibt es ja anregungen für die Klassenstrucktur.
Zitat:
Warum schreiben eigentlich 70% aller Deutschen das Wort immer falsch.
Michael Springwald
MFG Michael Springwald, Bitte nur Deutsche Links angeben Danke (benutzte überwiegend Lazarus) |
Zitat |
Registriert seit: 1. Dez 2002 Ort: Oldenburg(Oldenburg) 2.008 Beiträge FreePascal / Lazarus |
#4
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" ?
Michael Springwald
MFG Michael Springwald, Bitte nur Deutsche Links angeben Danke (benutzte überwiegend Lazarus) |
Zitat |
Registriert seit: 13. Dez 2003 Ort: Berlin 1.756 Beiträge |
#5
Zitat von mimi:
1: Eigenschafen:
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.
Zitat von mimi:
2: Strucktur:
Ist die strucktur bis jetzt sinvoller als die "alte" ? 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 |
Zitat |
Registriert seit: 1. Dez 2002 Ort: Oldenburg(Oldenburg) 2.008 Beiträge FreePascal / Lazarus |
#6
was meisnt du mit "setter" ?
Zitat:
Wichtig ist es halt, möglichst gut vorbereitet zu starten, Fehler vermeiden
Zitat:
Für Draw wäre dann noch interessant wohin du zeichnen lassen möchtest.
ich möchte auch nur das obj neu zeichen lassen was sich gerade ändert.
Zitat:
Ich weiß nicht ob du in deinem Tut auch schon was über Interfaces und abstrakte
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.
Michael Springwald
MFG Michael Springwald, Bitte nur Deutsche Links angeben Danke (benutzte überwiegend Lazarus) |
Zitat |
Registriert seit: 1. Dez 2002 Ort: Oldenburg(Oldenburg) 2.008 Beiträge FreePascal / Lazarus |
#7
das ist die "neue klasse" habe ein paar änderung gemacht die ich übersehen hatte
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;
Michael Springwald
MFG Michael Springwald, Bitte nur Deutsche Links angeben Danke (benutzte überwiegend Lazarus) |
Zitat |
Registriert seit: 13. Dez 2003 Ort: Berlin 1.756 Beiträge |
#8
Zitat von mimi:
was meisnt du mit "setter" ?
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 von mimi:
Zitat:
Für Draw wäre dann noch interessant wohin du zeichnen lassen möchtest.
ich möchte auch nur das obj neu zeichen lassen was sich gerade ändert.
Zitat von mimi:
habe ich. Aber ich weiß im moment nicht was ein Interfaces hier zu tuen hätte ich stelle mir ein interfaces immer so vor:
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. 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 von mimi:
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.. Gruß Der Unwissende |
Zitat |
Registriert seit: 1. Dez 2002 Ort: Oldenburg(Oldenburg) 2.008 Beiträge FreePascal / Lazarus |
#9
Zitat:
Ich verstehe dein Frage ehrlich gesagt nicht ganz. Was heißt denn "sein obj. selbst verwalten?". Genauer gesagt was soll denn verwaltet werden? Wenn du hier so etwas wie Kinder haben meinst, da würde ich dir auch zu einer TObjectList raten. Auch zu Interfaces, wenn du hier ein Interface hast, dass ein Add und ein Remove (oder Ähnliches) bietet, dann könntest du damit leicht in jeder Klasse die dieses Interface implementiert ein Objekt hinzufügen oder entfernen.
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:http://www.benibela.de 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
Michael Springwald
MFG Michael Springwald, Bitte nur Deutsche Links angeben Danke (benutzte überwiegend Lazarus) |
Zitat |
25. Dez 2005, 19:21 Erstellt von Amateurprofi | |
Dieser Beitrag wurde von r_kerber gelöscht. - Grund: Ist völlig OT! | |
Registriert seit: 13. Dez 2003 Ort: Berlin 1.756 Beiträge |
#10
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 |
Zitat |
Ansicht |
Linear-Darstellung |
Zur Hybrid-Darstellung wechseln |
Zur Baum-Darstellung wechseln |
ForumregelnEs ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.
BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus. Trackbacks are an
Pingbacks are an
Refbacks are aus
|
|
Nützliche Links |
Heutige Beiträge |
Sitemap |
Suchen |
Code-Library |
Wer ist online |
Alle Foren als gelesen markieren |
Gehe zu... |
LinkBack |
LinkBack URL |
About LinkBacks |