AW: Strafzeitenverwaltung in eigener Unit
Das liegt daran, dass die Eigenschaft Items deiner TPenalties-Klasse (worauf du mit dem []-Operator implizit zugreifst) von TObjectList geerbt ist. TObjectList wurde so konzipiert, dass es Objekte aller Arten speichern kann, deshalb wurde bei der Deklaration der "Urahn" aller Klassen unter Delphi, TObject, gewählt. Da du aber wie gesagt jedes erdenkliche Objekt in dieser Liste speichern kannst, beschwert sich Delphi: Denn es könnte ja etwas völlig anderes als eine TPenalty-Instanz dort gespeichert sein, und das gäbe dann einen Fehler.
Du hast zwei Möglichkeiten: Entweder du machst einen Typecast auf TPenalty, oder du überschreibst gleich in TPenalties die Items-Property. Das geht etwa so:
Delphi-Quellcode:
Natürlich ist es sinnvoll, in dem Zug auch gleich die Methoden Add, Remove etc zu überschreiben, sodass diese ebenfalls typensicher sind, sprich als Parameter TPenalty statt TObject entgegen nehmen. So sicherst du die Klasse auch gegen Bedienfehler von außen ab, denn solange der Nutzer der Klasse es nicht gerade mit Typecasts darauf anlegt, Fehler zu provozieren, schmeißt der Compiler beim Kompilieren jedes mal einen Fehler und bricht den Kompiliervorgang ab, wenn irgendwo ein falsches Objekt zugewiesen wird.
TPenalties = class(TObjectList)
private function GetItem(Index: integer): TPenalty; procedure SetItem(Index: integer; AItem: TPenalty); public // Siehe dazu die Online-Hilfe zum Stichwort Properties... property Items[Index: integer]: TPenalty read GetItem write SetItem; default; end; function TPenalties.GetItem(Index: integer): TPenalty; begin // per inherited wird der gleichnamige Getter von TObjectList aufgerufen, // das Ergebnis wird nach TPenalty gecastet Result := TPenalty(inherited GetItem(Index)); end; procedure TPenalties.SetItem(Index: integer; AItem: TPenalty); begin // Hier ist kein Typecast nötig, weil TObject der "Urahn" von allen Klassen // und somit auch TPenalty ist, daher also alle Klassen zu den Schnittstellen von // TObject kompatibel sind. inherited SetItem(Index, AItem); end; |
AW: Strafzeitenverwaltung in eigener Unit
Hallo,
vielen Dank für die helfenden Hinweise und das Codebeispiel. Ich denke, dass ich dabei wieder was gelernt habe! Ich würde nun gern Eure Meinung wissen, wie Ihr die laufenden Uhren verwalten/steuern würdet. Aktuell ist die laufende Hauptzeit über einen Timer gelöst. Schön ist sicher anders, aber ich wusste mir nicht anders zu helfen. Soll ich das Increasen/Decreasen der Strafzeitenuhren dann auch hier über den Timer machen, oder wäre das eher nicht so gut!?
Delphi-Quellcode:
//globale Deklaration
var original: TSystemTime; procedure TForm1.int_clockTimer(Sender: TObject); begin //check, how the clock should run case rad_direction.ItemIndex of 0 : begin // clock should run asc original.wsecond:= original.wSecond + 1; if original.wSecond = 60 then begin original.wSecond :=0; original.wMinute :=original.wMinute + 1; end; end; 1 : begin // clock should run desc //stop clock and end case, cause time is up if (original.wSecond = 0) and (original.wMinute = 0) then begin //stop timer int_clock.Enabled := false; end else begin if original.wSecond = 0 then begin original.wSecond := 59; original.wMinute := original.wMinute - 1; end else original.wsecond := original.wSecond - 1; end; end; end; //show the clock - internal lbl_mtime_int.Caption := Format('%.2d:%.2d', [original.wMinute,original.wSecond]); btn_set_data.Enabled := not(int_clock.Enabled); end; |
AW: Strafzeitenverwaltung in eigener Unit
Hallo,
Zitat:
Ich empfehle dir hierfuer uebrigens ein Observer-Pattern. Kurz eine Erklaerung: Du hast eine Klasse GameClock. Diese Methode kapselt einen Timer und hat eine Start/Stop-Methode. Start startet die Uhr, Stop haelt sie an. Beim Starten der Uhr schickst du dann eine Message an alle registrierten PenaltyClocks, dass diese auch starten. Beim Stop funktioniert das analog. Bei dieser Gelegenheit noch nen Hinweis: beachte dass du nie mehr als 2 Strafzeiten laufen lassen darfst. Ein kleines Beispiel: Mannschaft A kassiert 2 Minuten. PP beginnt, Mannschaft A kassiert nochmal 2 Minuten. Jetzt laufen beide Strafzeiten und A spielt in doppelter Unterzahl. Wenn jetzt nochmal eine Strafe fuer A ausgesprochen wird, landen die 2 Minuten auf der Uhr, werden aber nicht runtergezaehlt bis nicht eine der vorherigen Strafzeiten abgelaufen sind. Im Beispiel oben bedeutet das: dein Observer-Pattern darf nur die ersten beiden PenaltyClocks einer Mannschaft starten. Laeuft eine PenaltyClock aus, muss sie die erste nicht laufende PenaltyClock der eigenen Mannschaft starten. So, ich hoffe das macht noch halbwegs Sinn was ich da geschrieben habe ;) Greetz alcaeus |
AW: Strafzeitenverwaltung in eigener Unit
Hallo,
Zitat:
Zitat:
Zitat:
Zitat:
Zitat:
Zitat:
Die Uhrenklasse habe ich jetzt erstmal so aufgesetzt. Natürlich fehlen da noch die Funktionen "nach aussen hin".
Delphi-Quellcode:
unit unt_game_clock;
interface uses ExtCtrls; type TGameClock = class private GameClock : TTimer; public constructor Create; Procedure StartClock; Procedure StopClock; end; implementation constructor TGameClock.Create; begin inherited; end; Procedure TGameClock.StartClock; begin GameClock.Enabled := True; end; Procedure TGameClock.StopClock; begin GameClock.Enabled := False; end; end. |
AW: Strafzeitenverwaltung in eigener Unit
Hallo,
Zitat:
Zitat:
Code:
Ein paar kurze Erklaerungen: es gibt einen Timer fuer die Zeitmessung, sowie zwei Arrays von PenaltyClocks. Die Methode addPenaltyClock fuegt eine PenaltyClock der GameClock hinzu und uebergibt der PenaltyClock ein paar Informationen.
class GameClock
{ private timer; private homePenaltyClocks; private awayPenaltyClocks; public function create() { this->timer = new Timer; } public function addPenaltyClock(team, clock) { clock->team = team; clock->gameClock = this; if (team == 'home') { this->homePenaltyClocks->push(clock); } else { this->awayPenaltyClocks->push(clock); } } public function start() { this->timer->start(); for (i = 0; i < this->homePenaltyClocks->count() && i < 2; i++) { this->homePenaltyClocks[i]->start(); } for (i = 0; i < this->awayPenaltyClocks->count() && i < 2; i++) { this->awayPenaltyClocks[i]->start(); } } public function stop() { this->timer->stop(); for (i = 0; i < this->homePenaltyClocks->count() && i < 2; i++) { this->homePenaltyClocks[i]->stop(); } for (i = 0; i < this->awayPenaltyClocks->count() && i < 2; i++) { this->awayPenaltyClocks[i]->stop(); } } public function penaltyClockComplete(team) { // Erstes Element aus dem Array entfernen // Wenn dann immer noch 2 Strafzeiten da sind, die zweite starten. } } start() und stop() starten/stoppen die Zeitmessung sowie die der ersten beiden PenaltyClocks (soweit vorhanden). penaltyClockComplete() sagt der GameClock, dass eine Strafzeit abgelaufen ist und eine eventuell weitere gestartet werden muss (das darfst du dann selbst implementieren - ist aber auch keine Kunst).
Code:
Die PenaltyClock enthaelt einen eigenen Timer, da sie unabhaengig zur GameClock laufen muss.
class PenaltyClock
{ private timer; public gameClock; public team; public function create() { this->timer = new Timer(); } public function start() { this->timer->start(); } public function stop() { this->timer->stop(); } public function onTimerComplete() { if (!this->gameClock || !this->team) { return; } this->gameClock->penaltyClockComplete(team); } } start() und stop() brauchen ja keine Informationen. Im onTimerComplete()-Event wird dann (sofern team und gameClock gesetzt sind) der entsprechenden GameClock gesagt, dass eine Strafzeit fuer eine entsprechende Mannschaft abgelaufen ist. Das sollte das Prinzip ein bisschen naeher bringen. Der Code ist nicht der schoenste, aber nachdem du eh Delphi-Code brauchst musst du ihn sowieso neu schreiben - so dass auch weniger Code doppelt vorkommt ;) Zitat:
Zitat:
Zitat:
Greetz alcaeus |
AW: Strafzeitenverwaltung in eigener Unit
Moin,
@alcaeus: Vielen Dank für Deine Mühe. Dein Code riecht sehr nach php. :-) Ich werde ihn mir im Laufe des Tages mal anschauen und versuchen ihn zu implementieren bzw. zu verstehen. Versuchen deshalb, weil ich natürlich nicht ganz faul war. Ich poste hier mal meine bisherige Uhrenklasse. Da ist nun schon fast alles drin, wenngleich in Deinem letzten Post auch noch mal Hinweise drin waren, die ich auch wieder nicht auf dem Zettel hatte (z.b. interne Trennung von 2+2). Insofern läuft das mit der Zeit jetzt schon. Allerdings hat meine Version ein paar Pferdefüsse. - Intervall im Timer bei 1000 -> mir ist nicht klar, wie ich das mit 10 und dem Hochzählen machen soll - Alle Uhren laufen derzeit syncron. Somit kann es hier und da zu diversen kleinen Differenzen kommen - Der Timer im Hauptform steuert die Hauptuhr und liest die Daten aus der PenaltyList aus, die über einen anderen Timer (GameClock) gesteuert werden Gelöst ist schon - das man variabel sagen kann, wieviele Strafzeiten max. gleichzeitig laufen dürfen -- die anderen uhren "rutschen" dann nach - eine Ausgabe ob gerade Powerplay ist und welches Team das hat Und fairerweise hier noch mein Code.
Delphi-Quellcode:
So und jetzt schau ich mir Deins mal näher an.
unit unt_game_clock;
interface uses Windows, Dialogs, SysUtils, ExtCtrls, unt_penalties, unt_penalty, myGlobals, ShellApi; type TGameClock = class private GameClock : TTimer; //this is the timer max_RunningPenalties : byte; //this is a number of max. running penalties per team public Direction : byte; //this is the direction of the running clock IsPowerplay : Boolean; //this is a flag for powerplay PP_OnTeam : byte; //this is a flag for the team, which is under powerplay constructor Create; Procedure StartClock; Procedure StopClock; Procedure GameClockTimer(Sender: TObject); end; implementation uses Math; constructor TGameClock.Create; begin inherited; //create timer and init GameClock := TTimer.Create(nil); max_RunningPenalties := 2; isPowerplay := False; end; procedure TGameClock.GameClockTimer(Sender: TObject); var i, ListOffset : integer; TimeHolder : TSystemTime; h,m,s,msec : Word; IncreaseOffset : Boolean; int_team_a, int_team_b : byte; begin //init of variables int_team_a := 0; int_team_b := 0; ListOffset := 0; //walk over all penalties for i := 0 to PenaltyList.Count -1 do begin if not(PenaltyList.Items[i-ListOffset] <> nil) then exit; if PenaltyList.Items[i-ListOffset].Team = 'A' then inc(int_team_a); if PenaltyList.Items[i-ListOffset].Team = 'B' then inc(int_team_b); //here we check, if we have a powerplay-situation if ((int_team_a <= max_RunningPenalties) and (int_team_b <= max_RunningPenalties)) then begin //set isPowerplay true or false if int_team_a <> int_team_b then IsPowerplay := True else IsPowerplay := False; //set the team, which is on powerplay if int_team_a > int_team_b then PP_OnTeam := 1 else PP_OnTeam := 2; end; //here we check, if a team has more then the allowed max number of penalties //if yes => we dont count the timing for this penalty if ((PenaltyList.Items[i-ListOffset].Team = 'A') and (int_team_a <= max_RunningPenalties)) or ((PenaltyList.Items[i-ListOffset].Team = 'B') and (int_team_b <= max_RunningPenalties)) then begin IncreaseOffset := False; DecodeTime(StrToTime(PenaltyList.Items[i-ListOffset].CTime),h,m,s,msec); TimeHolder.wHour := h; TimeHolder.wMinute := m; TimeHolder.wSecond := s; TimeHolder.wMilliseconds := msec; case PenaltyList.Items[i-ListOffset].Direction of 0 : begin // clock should run asc TimeHolder.wsecond:= TimeHolder.wSecond + 1; if TimeHolder.wSecond = 60 then begin TimeHolder.wSecond :=0; TimeHolder.wMinute :=TimeHolder.wMinute + 1; end; end; 1 : begin // clock should run desc //delete that penalty, cause time is over if (TimeHolder.wSecond = 0) and (TimeHolder.wMinute = 0) then begin //delete it later, after sending out the 0:00 IncreaseOffset := True; end else begin if TimeHolder.wSecond = 0 then begin TimeHolder.wSecond := 59; TimeHolder.wMinute := TimeHolder.wMinute - 1; end else TimeHolder.wsecond := TimeHolder.wSecond - 1; end; end; end; //adwise the new CurrentTime PenaltyList.Items[i-ListOffset].CTime := Format('%.2d:%.2d:%.2d', [TimeHolder.wHour,TimeHolder.wMinute,TimeHolder.wSecond]); //we have to delete an item if IncreaseOffset then begin PenaltyList.Delete(i-ListOffset); inc(ListOffset); end; end; end; end; Procedure TGameClock.StartClock; begin GameClock.OnTimer := GameClockTimer; GameClock.Enabled := True; end; Procedure TGameClock.StopClock; begin GameClock.Enabled := False; end; end. |
AW: Strafzeitenverwaltung in eigener Unit
versuchs mal mit:
Delphi-Quellcode:
ungetestet, sollte aber so gehen...
type
TPenalties = class(TObjectList) private function GetItems(Idx: Integer): TPenalty; procedure SetItems(Idx: Integer; Value: TPenalty); public property Items[Idx: Integer]: TPenalty read GetItems write SetItems; end; ... function TPenalties.GetItems(Idx: Integer): TPenalty; begin Result := (inherited GetItems(Idx)) as TPenalty; end; procedure TPenalties.SetItems(Idx: Integer; Value: TPenalty); begin inherited SetItems(Idx, Value); end; Edit: hm, irgendwie hab ich die letzten Beiträge nicht gesehen... sorry... |
AW: Strafzeitenverwaltung in eigener Unit
Zitat:
Ich hab aber darauf geachtet, es so zu schreiben dass es relativ leicht verwendbar ist. Voraussetzung ist aber, dass Delphi Objektreferenzen speichert und keine Kopien der Objekte. Wie das gehandhabt wird hab ich nicht mehr im Kopf. Ich geh mal in Ruhe deinen Code durch - das dauert bei mir etwas laenger, da ich seit mehr als 4 Jahren (!) keine einzige Zeile Delphi geschrieben hab :oops: Greetz alcaeus |
AW: Strafzeitenverwaltung in eigener Unit
Zitat:
Zitat:
MfG Fabian |
AW: Strafzeitenverwaltung in eigener Unit
Zitat:
Zitat:
Greetz alcaeus |
Alle Zeitangaben in WEZ +1. Es ist jetzt 19:46 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