Projekt mit
1 €
unterstützen?
So geht das *:


Step 02 - OOP und was nun noch gesagt werden muss (Teil 2/2)


Wir Delphianer programmieren sehr gerne dynamisch. Daher könnte es sein, dass das Wort static erstmal total unbekannt ist, sofern es nicht von einer anderen Programmiersprache wie z.B. C++ oder Java bekannt ist.

Um es genau erklären zu können müssen wir uns zunächst mal anschauen was passiert wenn wir ein Objekt - eine instanz einer Klasse - erstellen.

Angefanngen beim compilieren:

Unser Programm weiß noch nicht genau, wann dieses Objekt erstellt bzw. der Speicher hierfür reserviert werden soll. Beim Klicken eines Buttons soll z.B. eine Meldung - ein eigener Dialog - gezeigt werden. Rein theoretisch wäre es doch nun sinnvoll, wenn genau dann beim Klicken dieser Speicher reserviert wird. Dies wäre der dynamische weg - d.h. ich bin selbst verantwortlich, dass es erstellt (Create) und wieder aus dem Speicher gelöscht (Destroy/Free) wird.

Andererseits - wie ist es wenn es sich bei diesem Dialog um ein eigenes Fenster aus einer eigenen Klasse handelt?

Es sollen Benutzereingaben erfasst werden, welche dann später - vom Hauptformular aus - ausgewertet werden sollen. (Okay, hierfür würden wir eher ein virtuelles Objekt als "Datenbank" benutzen) Worauf ich hierbei hinaus wollte: bereits beim Laden des Programmes wird - bei Standardeinstellungen - dieses "Dialog"sformular erstellt und ist von da an statisch im Speicher.

1. Mehrere Formulare - und wie Zugriffsfehler entstehen können

An folgendem einfachen Beispiel möchte ich hier auf einige wichtige Dinge mit dem Umgang von "mehreren Fenstern" hinweisen.

  • Hierfür erstellen wir zunächst ein neues Projekt, welches wir "LittleWindowGame" nennen. ("MainUnit" nicht vergessen!)
  • Nachdem wir das Formular "MainForm" benannt haben, fügen wir nun unter "Datei" -> "Neu" -> "Formular" unserem Projekt ein neues Formular hinzu, welches wir "RedForm" nennen. Die pas-Datei benennen wir mit "frmRedForm"
  • Nach dem gleichen Prinzip gehen wir für ein "BlueForm" sowie für ein "GreenForm" vor.
  • Die Namen der Formulare stellen gleichzeitig auch die Farbe des Hintergrundes dar.
  • Auf Red Green und Blue setzen wir jeweils ein TShape-Objekt und nennen es jeweils "shpLight". (ja, jedes hat den gleichen Namen!)
    Hiernach noch bei Shape "stCircle" einstellen und bei Width den Wert 50 eintragen.
  • Nachdem wir nun sicherheitshalber auf "Alles Speichern" geklickt haben, wenden wir uns dem Hauptformular zu:
    Wir erstellen per doppelklick auf das Ereignis "OnCreate" die MainFormCreate-Prozedur und tragen dort folgendes ein:
      with BlueForm do
      begin
        BorderStyle := bsNone;
        Color       := clBlue;
        Width       := 250;
        Height      := 250;
        Top         := 50;
        Left        := 50;
    
        shpLight.left        :=100;
        shpLight.top         :=100;
        shpLight.Brush.Color := clBlue;
    
        Show;
      end;
    
      // Hier die anderen Formulare...
    
      Left := 350;
      top  := 350;
    end;
    

    Das allergleiche machen wir sowohl mit GreenForm als auch mit RedForm und ändern jeweils die Farbennamen sowie die Links-Abstände wie folgt:
    Bei RedForm: 50;
    Bei GreenForm: 350;
    Bei BlueForm: 650;
  • Damit BlueForm und die anderen gefunden werden, müssen wir noch die anderen Units bei den Uses hinzufügen:
    implementation
    
    uses
      frmRedForm, frmGreenForm, frmBlueForm;
    
    Wenn wir das alles nun ordnungsgemäß und richtig gemacht haben, dann werden wir auf einen Fehler stoßen wie:
    "Im Projekt LittleWindowGame.exe ist eine Exception der Klasse EAccessViolation mit der Meldung 'Zugriffsverletzung bei Adresse 0044A2C3 in Modul 'LittleWindowGame.exe'. Lesen von Adresse 00000271' aufgetreten."
  • Dieser Fehler taucht auf, da wir uns folgendem Gedankengang entzogen haben:
    Wenn Speicher für Objekte reserviert und diese sozusagen erstellt werden, dann passiert das in einer bestimmten Reihenfolge.
    Im Projektquelltext können wir diese sehen und ggf. bearbeiten. (Projekt -> Quelltext anzeigen)
    Allerdings bearbeiten wir nichts, da sonst wieder ein kleiner ungewollter Nebeneffekt auftaucht, sondern wir verschieben alles in die Methode des OnShow-Ereignisses, welche wir im Objektinspektor noch erzeugen müssen.
  • Nun können wir das Programm ohne Probleme ausführen.
    Jetzt kommt die eigentliche Spielelogik:
    Es sollen alle Formulare nebeneinander angezeigt werden. (was schon passiert)
    Dann soll ein Timer (den wir im nächsten Schritt implementieren) alle n Millisekunden die Farben der Shapes ändern.
    Hiernach muss der benutzer auf das Formular klicken, welches diese angezeigte Farbe hat.
    Hat er es geschafft bevor quasi die Zeit um ist, dann kommt er weiter und der Timer wird um x millisekunden verkleinert.
    Hat er es nicht geschafft, ist das Spiel vorbei und n(anfang) - n(momentan) ist die Anzahl der Punkte.
  • Also, rann ans Werk:
    Wir fügen einen Timer (tmrGameTimer) beim Hauptformular ein und stellen das Intervall auf 4 Sekunden (4000 ms).
    Dann benötigen wir noch 2 Buttons:
    Der eine soll das Spiel starten (BtnStartGame), der andere soll das Programm schließen (BtnQuit). BtnQuit soll das Programm schließen. BtnStartGame soll die erste Farbe setzen sowie den Timer starten:
    procedure TMainForm.BtnStartGameClick(Sender: TObject);
    var
      col: TColor;
    begin
      case random(3) of  // Zufallsfarbe wählen
        0: col:= clRed;
        1: col:= clGreen;
        2: col:= clBlue;
      end;  // Farbe  setzen:
      RedForm.shpLight.Brush.Color := col;
      GreenForm.shpLight.Brush.Color := col;
      BlueForm.shpLight.Brush.Color := col;
      tmrGameTimer.Enabled := true;
    end;
    
  • Und nun zum Timer:
    Es soll erst abgefragt werden, ob die aktuelle Farbe gleich der des geklickten Formulars ist (die wir noch irgendwo zwischenspeichern müssen!),
    Hiernach soll entweder eine neue Farbe sowie das neue Intervall n gesetzt oder das Spiel beendet und die Punkte ausgegeben werden.
    Wir deklarieren also zunächst ein privates Feld in der TMainForm-Klasse und einen Setter:
      private
        fCurrentClickedColor : TColor;
      public
        procedure SetCurrentClickedColor( AColor: TColor);
    
    Hierzu implementieren wir die Methode:
    procedure TMainForm.SetCurrentClickedColor( AColor: TColor);
    begin
      fCurrentClickedColor := AColor;
    end;
    
  • Nun müssen wir dafür sorgen, dass dieser Wert auch gesetzt wird.
    Wir implementieren also in jedem Formular (ausgenommen dem Hauptformular) die OnClick-Methode, in der wir per MainForm.SetCurrentClickColor( Color) den Farbwert des eigenen Formulars zuweisen.
    (Achtung: Verbindung zu Mainform muss auch implementiert werden!)
  • Nun können wir den oben genannten Gedankengang einfach umsetzen.
    Da ihr auch etwas denken dürft, hier nur ein unvollständiger Teil des Pseudocodes:
      wenn MomentanGeclickteFarbe = BlauesFormular.Shape.Pinsel.Farbe dann
      starte
        SetzeNeueZufallsfarbe;
        VerringereIntervallDesTimersUm100;
      ende
      ansonsten
      starte
        DeaktiviereTimer;
        Anwendung.Meldungsbox(PChar('Du hast ' +
                                    IntToStr(4000 -
                                             TimerIntervall) +
                                    ' Punkte!') ,
                              'Game Over' ,
                              MB_OK+MB_ICONINFORMATION);
      ende;
    
  • Und schon ist das Spiel fertig - <Download Source>

Die Formulare sind somit statisch im Programm geladen worden.
Unser kleines Schlüsselwort static jedoch dient für eine ganz andere Sache:
Wir können damit quasi eine Klasse deklarieren, dessen Methoden und Eigenschaften ohne Instantiieren per TMyClass.MethodX benutzt werden können.

Wer nun von OOP immernoch nicht genug hat oder einfach noch etwas tiefer in die Materie eingreifen möchte, kann sich in der Borland-Referenz (Einfach in Turbo-Delphi die Hilfe öffnen und eine Zeile eingeben) folgende Themen mal anschaun:
ms-help://borland.bds4/bds4ref/html/ClassesAndObjectsOV.htm
ms-help://borland.bds4/bds4ref/html/ClassReferences.htm
ms-help://borland.bds4/bds4ref/html/Exceptions.htm
ms-help://borland.bds4/bds4ref/html/Methods.htm
Auch noch sehr interessant:
ms-help://borland.bds4/bds4ref/html/OperatorOverloads.htm

Ich hoffe ich konnte euch mit diesem Zweiteiler einen noch besseren Überblick zu den Wichtigsten Prinzipien in der OOP-Welt liefern.



Da das Kommentarmodul dieser Seite zur Zeit neu überarbeitet werden muss, sendet bitte alle Fragen, Anregungen oder Probleme mit Betreff zu welchem Thema es sich handelt an folgende Mailadresse:



www.marco-hetzel.de
www.delphi-lernen.de
www.lazarus-lernen.de

© 2006-2019 by Marco Hetzel , last modified 01.11.2018, 11:28

(* Unterstützung dient der Aufrechthaltung laufender Kosten für dieses Projekt.)