AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Netzwerke Delphi Pokerprojekt realisierung
Thema durchsuchen
Ansicht
Themen-Optionen

Pokerprojekt realisierung

Ein Thema von .chicken · begonnen am 28. Mär 2007 · letzter Beitrag vom 15. Mai 2007
Antwort Antwort
Seite 3 von 7     123 45     Letzte »    
Der_Unwissende

Registriert seit: 13. Dez 2003
Ort: Berlin
1.756 Beiträge
 
#21

Re: Pokerprojekt realisierung

  Alt 3. Apr 2007, 15:48
Zitat von .chicken:
Also wie schreibe ich ein Event für meinen Server, wenn ich ihn zur Laufzeit erstelle?
Willst Du hier wirklich das Event schreiben oder die Behandlung des Events?
Ich werde im folgenden einfach mal auf Beides eingehen. Das Ereignis an sich ist nichts, was Du wirklich programmieren musst. Du legst eigentlich nur fest, wann die Ereignisbehandlung ausgelöst wird. Das ist schon alles.
Bleibt das Problem der Ereignisbehandlung. Hier gibt es ganz verschiedene Ansätze. Der unter Delphi typische besteht in einem Callback. Callback kannst Du dabei wirklich als Rückruf übersetzen. Jmd. der sich für ein Ereignis interessiert hinterlässt seine "Nummer" (genau gesagt ist es eine Adresse) und wird "zurückgerufen", wenn das Ereignis eintritt.
An sich ist dies natürlich (mehr oder weniger) immer der Weg, den man verwendet. Der (hauptsächliche) Unterschied liegt darin, wie man nun die Rückrufnummer hinterlässt. Dabei ist der Delphi-typische Weg die Verwendung eines Methodenzeigers. Ein Methodenzeiger speichert die Adresse einer Methode. Das ist ein eigener Datentyp, der einfach eine Adresse speichert. Du weißt dann, dass eine solche Adresse auf eine Methode zeigt und wie deren Signatur aussieht. Du weißt also welche Parameter Du übergeben musst und was für ein Ergebnis Du bekommst (keins wenn es eine Procedure ist).
Ein Methodenzeiger wird wie folgt deklariert:
Delphi-Quellcode:
type
  TMethodenZeiger = procedure(Argument1: Typ1; ... ArgumentN: TypN) of object;
  // oder auch
  TMethodenZeiger2 = function(Argument1: Typ1; ... ArgumentN: TypN): TRueckgabeTyp of object;
Wie Du hier siehst, werden Methodenzeiger als Datentyp deklariert. Du gibst einfach einen Namen an und die eigentliche Deklaration besteht aus dem Schlüsselwort procedure oder function gefolgt von den Argumenten (soweit vorhanden) und für Funktionen dem Rückgabetyp. Der deutliche Unterschied zu normalen Methoden besteht hier schon darin, dass Du keinen Namen der Methode angibst. Zudem wird immer das Suffix of object angehangen.
Lässt Du Letzteres weg, so handelt es sich um einfach Funktionszeiger. Der Unterschied zwischen Funktions- und Methodenzeiger ist dabei recht einfach erklärt, Methoden gehören immer zu einem Objekt (Instanz einer Klasse), Funktionszeiger tun das nie! Beide sind in Delphi unterschiedlich aufgebaut und müssen deswegen unterschieden werden (Methodenzeiger verwenden ein verstecktes Argument, das Objekt).
Der Unterschied besteht also darin, dass Du einem Methodenzeiger nur Funktionen und Prozeduren (deren Adresse) zuweisen kannst, die zu der Instanz einer Klasse gehören. Umgekehrt kannst Du Prozeduren und Funktionen, die zu einer Klasse gehören aber nie einem Funktionszeiger zuordnen.

Wie gesagt, Delphi verwendet i.d.R. immer Methodenzeiger.
Wie man die deklariert hat, hast Du schon gesehen. Nach der Deklaration kannst Du die wie jeden anderen Datentypen auch verwenden und Variablen von diesem Typ anlegen. Diese Variablen können natürlich einen Wert annehmen und wie gesagt, dieser muss eine Adresse auf eine Methode (Prozedur oder Funktion eines Objekts) sein. Zudem muss die Signatur der Methode mit der deklarierten übereinstimmen (also müssen gleichviele Parameter in gleicher Reihenfolge und mit gleichem Typ übergeben werden).
Typischerweise legt man in Klassen alle Variablen mit geringster Sichtbarkeit (private) an (auf die Gründe gehe ich nicht näher ein, hier wäre ein Tutorial zur OOP nötig). Die eigentlichen Lese- und Schreibzugriffe delegiert man (Stichwort property). Ein Delphi property wirkt nach außen wie eine Variable, der Zugriff kann jedoch an eine Methode oder Variable delegiert werden.

Delphi-Quellcode:
type
  TKlasse = class(TObject)
    private
      FVariable: TTyp;
    protected
      procedure setVariable(const FValue: TTyp);
    public
      property Variable: TTyp read FVariable write setVariable;
      property VariableRO: TTyp read FVariable;
  end;
So ungefähr könnte das dann aussehen. Hier wird eine private Variable FVariable vom Typ TTyp angelegt. Den gleichen Typ haben die beiden properties (aber andere Namen). Dem Schlüsselwort property folgt etwas, dass wie eine normale Variablendeklaration aussieht (property Variable: TTyp). Dem wiederum folgt die Delegation des Lesens und/oder Schreibens (mindestens eine Eigenschaft muss hier delegiert werden). Im ersten Fall würde beim Lesen von Variable direkt die Instanzvariable FVariable gelesen werden. Würdest Du Variable einen Wert zuweisen (schreiben), dann würde hier die Methode setVariable aufgerufen werden. Der Parameter hat dabei automatisch den Wert, den Du setzen wolltest.
Hier siehst Du auch gleich warum man das macht, so ist VariableRO ReadOnly. Hier wurde nur das Lesen delegiert. Würdest Du versuchen diesen Wert für eine Instanz zu schreiben, wird Dir ein Fehler (schon zur Compilezeit) gemeldet. Aber auch das Delegieren macht Sinn. So kann setVariable prüfen, ob der übergebene Wert überhaupt gültig ist. Dies kann wichtig sein, wenn es Einschränkungen der gültigen Werte gibt. Auch das Lesen eines Wertes kann natürlich an eine Funktion delegiert werden. So wäre z.B. eine Eigenschaft Mittelwert denkbar, die Du natürlich leicht bei Bedarf berechnen kannst (statt sie in einer Variable zu speichern und bei allen Änderungen zu aktualisieren).

Ja, das gleiche wird meist auch mit Methodenzeigern gemacht. Allerdings werden die Zugriffe hier meistens direkt an die Variable deklariert (nur damit Du dich im Folgenden nicht wunderst).

So, alles zusammen ergibt jetzt die Ereignisbehandlung. Du legst einfach eine Klasse an, die ein property OnEventX besitzt. Dieses ist vom Typ ein Methodenzeiger und speichert die Rückrufnummer für die Ereignisbehandlung (in einer Variable).
Tritt jetzt Dein Ereignis ein, so schaust Du nach, ob eine gültige Rückrufnummer hinterlegt wurde. Ist dies der Fall, rufst Du dort an und teilst das Ereignis mit. Ist dies nicht der Fall, so kannst Du niemanden rückrufen und musst entsprechend nichts machen.
Das ganze mal komplett:
Delphi-Quellcode:
type
  TRückruf = procedure(const arg1: String) of object;

  TCallMe = class(TObject)
    public
      procedure callMe(const t: String);
  end;

  TKlasseMitEreignis = class(TObject)
    private
      FRückrufAdresse: TRückruf;
      ...
    public
      procedure doFoo;
      ....
      property OnEreignis: TRückruf read FRückrufAdresse write FRückrufAdresse;
  end;
Das sind jetzt erstmal nur die Datentypen. Du hast einfach einen Datentypen als Methodenzeiger, eine Klasse, deren Instanzen zurückgerufen werden können und eine Klasse, die die Rückrufe durchführt, sobald etwas bestimmtes passiert. In der letzten ist die weitere Funktionalität durch eine Methode doFoo angedeutet. doFoo könnte z.B. Auslöser der Ereignisbehandlung sein.
Die Implementierung von TCallMe ist hier völlig egal. Stell Dir einfach vor, dass die Klasse ein ShowMessage mit dem Argument t macht, sobald die Methode callMe aufgerufen wird.
Bleibt noch der Aufruf der Ereignisbehandlung:
Delphi-Quellcode:
procedure TKlasseMitEreignis.doFoo;
begin
  ...
  // Benachrichtigung
  // prüfen ob eine gültige Rückrufadresse zugewiesen wurde
  if assigned(OnEreignis) then
  begin
    // Rückruf einer Prozedur, die ein Argument vom Typ String bekommt
    self.OnEreignis('WAS AUCH IMMER');
  end; // if assigned(OnEreignis)
end;
So sieht dann einfach der Rückruf aus. Du kannst auf die Variable, die vom Typ ein Methodenzeiger ist wie auf eine normale Methode zurückgreifen. Mit dem assigned wird überprüft, ob die Adresse <> nil ist. Dies ist der Fall, sobald einmal eine gültige Adresse zugewiesen wurde. Nil (0) ist die einzigste verbotene Adresse. Auf einem 32-Bit Rechner bleiben damit (2^32 - 1) Adressen übrig (so gute 4,2 Mrd.). Das heißt aber nicht, dass jede Adresse <> nil gültig ist. Weißt Du eine Adresse zu, die zu einem Objekt gehört, so ist die nur gültig, bis Du das Objekt löscht. Du solltest Dich dann vor dem Löschen des Objekts darum kümmern, dass Du dort, wo es zurückgerufen wird die Rückrufnummer wieder auf nil setzt. Ansonsten bleibt die alte Rückrufnummer gespeichert, aber der Anschluss, der zurückgerufen wird wurde schon entfernt. Das gibt dann ein Problem (eine Exception).

Zu guter Letzt bleibt noch das setzen der Variable. Das schauen wir uns gleich am Beispiel an:
Delphi-Quellcode:
var klasseMitEreignis: TKlassesMitEreignis;
    rückrufKlasse: TRückruf;
begin
  // neue Instanzen erstellen
  klasseMitEreignis := TKlasseMitEreignis.Create;
  rückrufKlasse := TRückruf.Create;

  // eigentliches Registrieren der Rückruf-Adresse
  klasseMitEreignis.OnEreignis := rückrufKlasse.callMe;

  ....
end;
Natürlich solltest Du die Instanzen nicht in lokalen Variablen speichern, wie es hier der Fall ist, sonst wären die nach dem Verlassen der Methode eh unerreichbar und sollten hier schon wieder frei gegeben werden (anders gesagt, das Beispiel zeigt etwas unsauberes, nicht so nachmachen ).
Das Prinzip sollte aber klar sein.

Eine Sache ist hier jetzt aber ganz schlecht! Wie gesagt, es ist der Delphi-Standardweg. Trotzdem hast Du das Problem, dass Du nur eine Variable hast, also nur eine Rückrufadresse speichern kannst. Natürlich kannst Du für jede mögliche Rückrufadresse eine eigene Variable vorsehen, aber das verschiebt nur das Problem (man weiß nicht immer wie viele Spieler wirklich am Spiel teilnehmen wollen). Besser ist das Observer-Pattern zu verwenden.
Dieses Entwurfsmuster beschreibt zwei Rollen, das Observable (beobachtbares Objekt) und die Observer (Beobachter). Ein Observable bietet dabei die Möglichkeit, dass sich Beobachter über eine bestimmte Schnittstelle registrieren und wieder deregistrieren können. Observer registrieren sich also beim Observable und alle registrierten Observer werden werden vom Observable zurückgerufen. Wie das genau geschieht (wie die registrierten Observer verwaltet und rückgerufen werden) ist dabei nicht durch das Pattern vorgegeben (Pattern definieren nur ein Problem und eine allgemeingültige Lösung, die unabhängig von der Implementierung ist!). Somit ist nur eindeutig bestimmt, was für eine Technik verwendet wird.
Wie Du es z.B. in Delphi realisieren kannst, kannst Du dem einen Thread (hatte den Link denke ich schon gepostet) entnehmen.
  Mit Zitat antworten Zitat
.chicken

Registriert seit: 5. Dez 2006
459 Beiträge
 
#22

Re: Pokerprojekt realisierung

  Alt 3. Apr 2007, 16:08
Oh mein Gott, wie kompliziert ist das denn...ich will doch nurn Ereignis erstellen o.O

Wo schreib ich denn jetzt zB rein was passiert wenn das Ereignis in Kraft tritt?
Sorry aber das kapier ich grad ma garnich!

Trotzdem danke fuer diene sehr ausfuehrliche Antwort!
  Mit Zitat antworten Zitat
Der_Unwissende

Registriert seit: 13. Dez 2003
Ort: Berlin
1.756 Beiträge
 
#23

Re: Pokerprojekt realisierung

  Alt 3. Apr 2007, 19:28
Zitat von .chicken:
Oh mein Gott, wie kompliziert ist das denn...ich will doch nurn Ereignis erstellen o.O

Wo schreib ich denn jetzt zB rein was passiert wenn das Ereignis in Kraft tritt?
Sorry, aber das ist fast schon eher ein Thema für einen eigenen Thread. Was genau hast Du denn bisher überhaupt verstanden (es haben ja schließlich schon andere in anderen Threads versucht zu erklären)? Das solltest Du an sich immer sagen, da das wieder neu erklären nicht wenig Aufwand mit sich bringt. Du hast ja schon gesagt, dass Du irgendwo geschaut hast, schön ist es dann, wenn Du noch ein wenig mehr sagst, wo Du nicht weiter gekommen bist/was Du dort nicht verstehst.

Um es hier nochmal einfach zu sagen (gelöst vom Code), Du hast zwei Rollen, Server und Client. Der Server kennt eintretende Ereignisse genau und benachrichtigt alle, von denen er weiß, dass sie sich dafür interessieren. Die Clienten wiederum registrieren/verbinden sich mit dem Server. Das heißt, dass sie sagen "Hallo, ich bin XYZ, bitte benachrichtige mich bei Ereignissen".
Das ganze muss der Server sich merken (der muss ja wissen wer alles benachrichtigt werden möchte). Dazu schreibt er einfach alle Interessenten in eine Liste. Tritt jetzt das Ereingis ein, so schaut der Server in diese Liste. Ist die Leer, will's keiner wissen, er hat nichts zu tun. Sonst geht der einfach alle durch, die in der Liste stehen und benachrichtigt die.
Beendet ein Client das Spiel, dann meldet der sich einfach beim Server ab und damit wird sein Name dann von der Liste genommen.

Das ist die grobe Idee. An sich ist das aber ein sehr konkretes Beispiel (und natürlich auf dein Pokerspiel bezogen). Abstrakter würde man nicht von einem Server und Clienten sprechen, sondern davon, dass es einen gibt, der Benachrichtigt (Observable) und keinen, einen oder viele die benachritigt werden wollen (Observer). Die Anzahl der Observer ist nicht bekannt (Meldet sich ein Spieler, 10 oder 1000?), aber auch egal. Jeder der sich meldet kommt auf die Liste und jeder der sich abmeldet kommt wieder runter. Hat man also irgendeine Möglichkeit jmd. auf die Liste zu setzen und zu entfernen, kann man so beliebig viele (eben auch keinen) benachrichtigen, sobald ein Ereignis eintritt.
Wer wen worüber benachrichtigt ist erstmal egal, das Prinzip ist immer das gleiche.

Hast Du das Prinzip soweit verstanden? Wenn nicht nachfragen!

Das ganze musst Du jetzt noch in Code umsetzen. Dabei gibt es verschiedene Probleme. Eine Trennung kann man hier sofort sehen, es muss Objekte geben, die sich benachrichtigen lassen wollen (die Observer) und etwas, dass die Benachrichtigung auslöst (Observable). Das Observable-Objekt muss zudem eine Möglichkeit haben, dass sich hier jmd. für eine Benachrichtigung melden/abmelden kann.

Das Problem dabei ist, dass Du (wie gesagt) nicht weißt, wer jetzt eigentlich benachrichtigt werden möchte. Mal ist sind es Spieler A, B und C, dann wieder D, E und F und dann A und E. Das Problem, dass Du nicht weißt wieviele es sind lässt sich leicht über geeignete Strukturen lösen. Hier wäre es sicherlich die Liste. Eine Liste speichert einfach eine beliebige Anzahl von gleichartigen Elementen, entspricht ein wenig einem Array, nur ohne Größenbeschränkung.
Problematischer ist, dass Du noch nicht weißt, wen Du benachrichtigen sollst. Hier musst Du Dir etwas überlegen, das man als Schnittstelle bezeichnen könnte/würde. Diese Schnittstelle ist verbindlich, sie legt fest, wie Du jmd. ansprechen kannst, der benachrichtigt werden möchte. Dabei musst Du alle Informationen speichern, die dazu nötig sind und wissen, wie Du über das Ereignis benachrichtigst.
Stell Dir das einfach wie in einem Call-Center vor. Hier können sich Leute melden, die über den Verkaufstart der PS4 informiert werden wollen. Jetzt rufen die an und hinterlassen ihre Telefonnummer. Dazu müssen sie eine Möglichkeit haben, sich zu melden (die Telefonnummer für die Anmeldung). Das Call-Center speichert irgendwie die Nummern (wie ist egal).
Natürlich muss es auch eine Möglichkeit geben, dass Du Dich wieder abmeldest, z.B. weil Du die X-Box 5D gekauft hast und Dich die PS4 nichtmehr interessiert.
Startet der Verkauf, gehen die einfach die Liste durch und rufen jeden an der drauf steht. Jetzt müssen sie Dir aber noch mitteilen worum es geht. Da ist es dann gut, wenn Du auch verstehst was die meinen. Nach Möglichkeit solltest Du also jmd. am Telefon haben, der eine Sprache spricht, die Du verstehst. Kann auch sein, dass Du Dir noch denken kannst, dass der Verkaufsstart auf japanisch angekündigt wurde, ein Programm kann das nicht. Hier gibt es nur verstanden oder nicht verstanden.

Am Besten überlegst Du Dir erstmal, was für Ereignisse Du im Moment berücksichtigen möchtest. Die Fragen die Du dabei stellen/beantworten solltes sind:
  • Was für ein Ereignis tritt ein
  • Wer wird benachrichtigt
  • Wer benachrichtigt

Poste erstmal die Ereignisse, dann kann man das leichter an einem Beispiel erklären. Und ansonsten frag einfach bei einzelnen Punkten, die Du nicht verstanden hast nach (ggf. halt immer nach dem nächsten Stück usw).
  Mit Zitat antworten Zitat
.chicken

Registriert seit: 5. Dez 2006
459 Beiträge
 
#24

Re: Pokerprojekt realisierung

  Alt 3. Apr 2007, 19:39
Also ich hab vom Server noch nicht viel!

Delphi-Quellcode:
unit Server;

interface

uses Controller;

type
  TServer = class(TServerSocket)
  Private
  Public
    constructor Create;
  end;

var
  Controller: TController;
  Server: TServer;

implementation

constructor TServer.Create;
begin
  inherited Create;
  Controller := TController.Create;

end;

end.
Ich dachte jetzt eigentlich, dass ich vielleicht irgendwie sowas schreiben kann:
Delphi-Quellcode:
  MyEvent: Procedure (Sender: TObject) of Object; //richtig so? :D

  Server.onClientRead := MyEvent;

  procedure TForm1.MyEvent(Sender:TObject);
  begin
    blablabla;
  end;
Sodass wenn eine Nachricht eingeht "blablabla" ausgeführt wird.
Wie realisier ich das nun? Weil eigentlich müsste TServerSocket doch onClientRead kennen oder nicht? Aber die Auto-Vervollständigung gibt da garnix aus....


Verstehste jetzt wo mein Problem is? Wie der Server arbeitet hab ich im groben schon verstanden!

Danke für deine Hilfe!
  Mit Zitat antworten Zitat
Der_Unwissende

Registriert seit: 13. Dez 2003
Ort: Berlin
1.756 Beiträge
 
#25

Re: Pokerprojekt realisierung

  Alt 3. Apr 2007, 20:54
Zitat von .chicken:

Ich dachte jetzt eigentlich, dass ich vielleicht irgendwie sowas schreiben kann:
Delphi-Quellcode:
  MyEvent: Procedure (Sender: TObject) of Object; //richtig so? :D

  Server.onClientRead := MyEvent;
Hoppla, da ist einiges durcheinander geraten.
MyEvent: Procedure... ist ganz schlecht! Der Doppelpunkt legt den Typ einer Variable fest. Dieser kann nicht einfach vom Typ procedure... sein, das würde zu einem Problem führen, dass ich nicht näher erläutern möchte. Einfach gesagt würden zwei Variablen mit diesem Typ nie kompatibel sein, da Delphi keinen einheitlichen Typen annehmen würde (wie gesagt, egal).
Du müsstest erst einen Datentypen erzeugen:
Delphi-Quellcode:
type
  TMyEvent = procedure(Sender: TObject) of Object;
Dann kannst Du Variablen von diesem Typen erstellen:
Delphi-Quellcode:
var
  variable: TMyEvent;
Ich hoffe Du siehst den Unterschied, so wie die nötigen Schlüsselwörter. An sich sollte jeder Datentyp auch ein Präfix (T für Typen, P für Zeiger) enthalten. Methodenzeiger bekommen ein T, da es sich um Referenzen handelt. Nur explizite Zeiger (Datentyp Pointer oder Dinge mit ^ wie ^Integer, ^Byte, ...) bekommen ein P vorgesetzt!
Damit ist immer klar, wann Du einen Typen meinst und wann eine Methode/Variable oder sonst was.

Wichtig ist aber auch hier, dass Du die zwei Seiten (Observable und Observer) unterscheidest. Die Benachrichtigung wird bereits durch TServerSocket ausgelöst. Das heißt, TServerSocket ist bereits ein fertiger Observer. Was noch fehlt ist die Methode, die benachrichtigt werden soll, also der Observer.
Welche Signatur die Methode haben muss kannst Du der OH entnehmen, dort unter Ereignisse findest Du das OnClientRead-Event und dessen Datentyp. Folgst Du dem, so siehst Du welche Argumente (z.B. Sender: TObject bei einem TNotifyEvent) Du übergeben musst. Ich gehe mal davon aus, dass Du da schon nachgeschaut hast und es sich hier um eine Methode handelt, die ein Argument von TObject bekommt.

Streich die beiden Zeilen, die ich oben gepostet habe und dann stimmt auch der Anfang
Delphi-Quellcode:
  procedure TForm1.MyEvent(Sender:TObject);
  begin
    blablabla;
  end;
Das kannst Du so stehen lassen, da ist alles korrekt. Was Du nun hast sind beide Seiten, TServerSocket bietet eine Möglichkeit jmd. zu benachrichtigen und TForm1 hat eine Methode, die benachrichtigt werden kann (TForm1.MyEvent). Was noch fehlt ist das Verknüpfen/Registrieren, so dass TServerSocket weiß, dass TForm1.MyEvent zurück gerufen werden soll.
Ok, jetzt wird mir klar was Du mit der Zeile meintest:
server.onClientRead := MyEvent; Wobei Server eine Instanz von TServer sein muss und MyEvent eben die Methode von TForm1 (also die Zuweisung in einer Methode von TForm1 aufgerufen wird). Hier käme z.B. das OnFormCreate in Frage (wenn Server bereits erstellt wurde).

Hier noch eine Bitte, bei solchen Zeilen wäre es immer schön, wenn Du ein wenig den Kontext angeben würdest. Wie Du gesehen hast ist (mir) hier nicht klar, was für einen Typ Server hat (usw.).
  Mit Zitat antworten Zitat
.chicken

Registriert seit: 5. Dez 2006
459 Beiträge
 
#26

Re: Pokerprojekt realisierung

  Alt 3. Apr 2007, 21:29
Edit: Natürlich doof wenn man die uses Klausel vergisst -.-

Trotzdem funzt es noch nicht wie ich will, habs nun nochmal n bissl geändert:
Delphi-Quellcode:
unit Server;

interface

uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ComCtrls, Spin, Controller, ScktComp;

type
  TMyServer = class(TServerSocket)
  Private
  Public
    constructor Create;
    procedure MyReadEvent(Sender: TObject; Socket: TCustomWinSocket);
  end;

var
  Controller: TController;
  Server1: TMyServer; //is das nicht n bisl komisch oder falsch? wenn man dann noch aufs oncreate ereignis guckt, wo dann der Server1.onClientRead zugewiesen wird...das is doch sicher nich ganz sauber oder? müsste ich nicht eigentlich im oncreate einfach TMyServer.onClientRead angeben? (das funzte aber nicht)

implementation

constructor TMyServer.Create;
begin
  inherited Create; //Hier sagt er "Not enoough actual Parameters"
  Controller := TController.Create;
  Server1.onClientRead := MyReadEvent;
end;

procedure TMyServer.MyReadEvent(Sender: TObject; Socket: TCustomWinSocket);
begin
  Showmessage('Klappt');
end;

end.
So ich glaube dass es jetzt eigentlich klappt, aber beim constructor gibt er immer n Fehler aus! (siehe Kommentar)

Außerdem gibt er ne komische Warnung aus:
"Method Create hides virtual method of base type TServerSocket"

Daraus werd ich noch nicht schlau!
  Mit Zitat antworten Zitat
.chicken

Registriert seit: 5. Dez 2006
459 Beiträge
 
#27

Re: Pokerprojekt realisierung

  Alt 4. Apr 2007, 11:53
Also, hab jetzt alles nochmal ueberarbeitet und auch einiges verbessern können!
Habe aber immernoch einen Fehler! Ich häng das Projekt einfach mal an!

(Hab bisher eigentlich nur die 6Units "Server", "Client", "Controller", "Deck", "Karte", "Spieler" geschrieben aber hab die nun zum Testen und kompilieren mal in ein Projekt eingebunden!)

Startet das Programm einfach mal und klickt auf Start Server. Dann kommtn Fehler und ich weiss nicht warum!
Irgendwas mit Zugriffsverletzung aber was weiss ich nicht!
Angehängte Dateien
Dateityp: rar test_748.rar (210,8 KB, 9x aufgerufen)
  Mit Zitat antworten Zitat
Der_Unwissende

Registriert seit: 13. Dez 2003
Ort: Berlin
1.756 Beiträge
 
#28

Re: Pokerprojekt realisierung

  Alt 4. Apr 2007, 12:15
Zitat von .chicken:
Startet das Programm einfach mal und klickt auf Start Server. Dann kommtn Fehler und ich weiss nicht warum!
Irgendwas mit Zugriffsverletzung aber was weiss ich nicht!
Sorry, aber ich muss Dir echt ein Tutorial über die Objekt Orientierte Programmierung (OOP) und Delphi empfehlen. Das hilft Dir sicherlich weiter (und die zu kennen ist an sich nicht falsch).
Ich glaube Dir ist der Unterschied zwischen Klasse und Exemplar noch nicht ganz klar.

Die Variable aServer in der Unit Main, speichert den Verweis auf ein Exemplar. Die Klasse TMyServer ist nur eine Klasse. Rufst Du den Konstruktor der Klasse TMyServer auf, so wird ein Exemplar erzeugt und der Verweis zurückgegeben (wie bei einer Funktion).
aServer.Create deutet der Compiler jetzt so, dass Du für das Exemplar aServer die Funktion Create aufrufen möchtest. Das Problem ist aber, dass Du aServer natürlich noch gar kein Exemplar zugewiesen hast.
Die korrekte Form wäre also
aServer := TMyServer.Create; Danach ist in aServer ein Verweis auf dieses neue Objekt gespeichert. Das heißt, dass Du irgendwann, sobald Du aServer einen anderen Wert zuweist oder es nicht mehr brauchst, aServer.Free aufrufen musst (um den Speicher wieder zu säubern).
Wie Du damit schon siehst, sobald in aServer ein gültiger Verweis steht, kannst Du dann auch direkt auf die Methoden dieser Instanz zugreifen. Der Konstruktor wird aber immer direkt für eine Klasse aufgerufen (also TXYZ.Create) und das Ergebnis einer Variablen zugewiesen. Mit anderen Methoden solltest Du das nie tun! (es gibt statische Methoden, aber die sind ein anderes Thema).
  Mit Zitat antworten Zitat
.chicken

Registriert seit: 5. Dez 2006
459 Beiträge
 
#29

Re: Pokerprojekt realisierung

  Alt 4. Apr 2007, 12:25
Ach scheiße Sowas passiert mir immer wieder! Ja mit dem Objekt-Orientierten-Programmieren is schon richtig! Bei vielen Dingen weiß ich immer nich ganz was gemeint ist und unser InfoLehrer hat eh keine Peilung was Erklären überhaupt bedeutet!
Er sagt immer nur: "Und eure Aufgabe ist jetzt euch zu dem Thema Infos aus dem Internet zu suchen! Das ist auch ein Teil der Informatik! Blabla..."

Naja ich infomier mich da mal und wenn du ein gutes Tut kennst kannstes mir gerne mitteilen
(Hoffe das ist nicht zu lang... )

Edit: Ist der Code ansonsten denn auch so schlimm?
  Mit Zitat antworten Zitat
Der_Unwissende

Registriert seit: 13. Dez 2003
Ort: Berlin
1.756 Beiträge
 
#30

Re: Pokerprojekt realisierung

  Alt 4. Apr 2007, 12:32
Zitat von .chicken:
Naja ich infomier mich da mal und wenn du ein gutes Tut kennst kannstes mir gerne mitteilen
Ich kenne leider überhaupt keins (das ich persönlich als gut empfinde). Heißt nicht, dass es die nicht gibt! Nur als ich damals (als ich die OOP noch nicht verstanden hatte) danach suchte, gingen viele Erklärungen nicht über "Es gibt Klassen und Vererbung" hinaus. Was auch immer Du findest sollte auf jeden Fall das Thema Kapselung und Abstraktion beinhalten. Gerade diese beiden Dinge findest Du immer wieder (nicht nur in der OOP) und sie machen einige Dinge leichter (sauberer, wartbarer, lesbarer,...)

Zitat von .chicken:
Edit: Ist der Code ansonsten denn auch so schlimm?
Hab mir nichts weiter angeschaut, nur die main und da ist ja nicht viel drin.
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 3 von 7     123 45     Letzte »    


Forumregeln

Es 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

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 09:36 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz