Entwickler-Ecke
Delphi Language (Object-Pascal) / CLX - procedure zur laufzeit definieren
IhopeonlyReader - Di 02.04.13 15:23
Titel: procedure zur laufzeit definieren
Guten Tag,
ich versuche gerade eine Procedure zur Laufzeit zu ändern.. vorerst ist dies auch möglich.. Beispiel
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24:
| type EinBeispiel=class(TObject) Auszufuehren: Boolean; OnAusfuehren: procedure; end;
var eT: EinBeipsiel;
prcedure Test1; begin showmessage('Hi'); end;
procedure Test2; begin showmessage('toll'); end;
eT.OnAusfuehren := Test1; eT.OnAusfueren; |
Das klappt alles einwandfrei... jedoch würde ich das gerne so gestalten
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12:
| procedure GibAus(Text: String; UnNochwas: Boolean); begin end;
eT.OnAusfuehren := GibAus(Edit1.Text, Checkbox1.Checked);
|
... es wird vom Compiler die Fehlermeldung ausgegeben:
"inkompatible typen 'Procedure' und 'procedure'"
was mich persönlich verwirrt...
da es viele Möglichkeiten gibt, und ich nicht alle abspeichern will (alle möglichen variablen in dyn. Arrays abspeichern, proceduren nummern zuweisen und auf abruf entsprechend einsetzen)
ist sowetwas möglich, wie ich es vorhabe?
Delete - Di 02.04.13 15:50
IhopeonlyReader hat folgendes geschrieben : |
Guten Tag, ich versuche gerade eine Procedure zur Laufzeit zu ändern. |
Und wozu soll das gut sein?
IhopeonlyReader - Di 02.04.13 15:59
Perlsau hat folgendes geschrieben : |
Und wozu soll das gut sein? |
Um allgemin gültige Typen zu schreiben :D
z.B. für Mapeditoren, wobei es dann Prozeduren wie
Feldbetreten
Feldverlassen
gäbe...
da es verschiedene Arten von "Feldern" gibt, und alle dieselben proceduren besitzen, fände ich es sehr umständlich ein Typ mit abstrakten Methoden zu schreiben, da sich ein anderer Typ auf den Typ Feld bezieht...
Beispiel
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17:
| Type TMap=class Felder: Array of Array of TFeld; procedure zeichnen; end;
type TFeld=class Feldbetreten: procedure; Feldverlassen: procedure; zeichnen: procedure; end;
For C:=0 to High(Felder) do For C1:=0 to High(Felder[C] do Felder[C,C1].zeichnen; |
die procedure zeichnen vom Typ TFeld könnte z.B. sein: ZeichneGras(clgreen); oder zeichneHausTeil(A1); oder auch nur procedure leer; (ohne Parameter)
das Problem ist, es ist immer die selbe "standart prozedure mit FESTEN Parametern", ich könnte natürlich bei nur 3 proceduren auch 3 variablen anlegen
einmal: eineFarbe: TColor;
einHausTyp: THaus;
procedureNR: Integer;
dann müsste ich für die erste procedure (zeichneGras)
eineFarbe auf clgreen setzen und procedureNR den Wert 1 zuweisen...
auf abruf würde dann folgendes passieren:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9:
| procedure zeichnen: begin case procedureNr of 1: ZeichneGras(eineFarbe); 2: ZeichneHausTeil(einHausTyp) 3: leer; else end; end; |
bei vielen Proceduren mit vielen verschiedenen Parametern sehr umständlich
wenn mann das ganze jetzt in viel größeren Stile machen würde, wäre es sehr umständlich z.B. verschiedene Feldarten (gras, haus...) in einzelne typen zu legen...
Abstract gestalten ist hier ebenfalls wergen der unterschiedlichen Parameter nicht möglich
jfheins - Di 02.04.13 16:32
Tja, da würde ich empfehlen: In TFeld richtige Methoden als virtual deklarieren. In einem TGrasFeld ableiten und per override implementieren. ;-)
Gausi - Di 02.04.13 16:52
Auch wenn die Möglichkeiten der Objektorientierten Programmierung vermutlich sinnvoller sind: Für sowas muss man sich einen eigenen Typ definieren:
Delphi-Quelltext
1: 2: 3:
| TMeineProzedurenMitSpeziellenParameter = procedure(aParam: String; bParam: Integer; cParam: Boolean); TMeineProzedurenMitSpeziellenParameter = procedure(aParam: String; bParam: Integer; cParam: Boolean) of Object; |
IhopeonlyReader - Di 02.04.13 16:59
jfheins hat folgendes geschrieben : |
Tja, da würde ich empfehlen: In TFeld richtige Methoden als virtual deklarieren. In einem TGrasFeld ableiten und per override implementieren. ;-) |
Das Problem: dann ist, wenn man ein Object vom Typ TMap erstellt und dann Map.zeichnen aufruft, leider das ganze Schiefläuft, da die Klasse TMap auf das allgemeine TFeld zurückgreift...
Gausi hat folgendes geschrieben : |
Auch wenn die Möglichkeiten der Objektorientierten Programmierung vermutlich sinnvoller sind: Für sowas muss man sich einen eigenen Typ definieren:
Delphi-Quelltext 1: 2: 3:
| TMeineProzedurenMitSpeziellenParameter = procedure(aParam: String; bParam: Integer; cParam: Boolean); TMeineProzedurenMitSpeziellenParameter = procedure(aParam: String; bParam: Integer; cParam: Boolean) of Object; | |
nur was bringt mir das? soll ich dann ganz viele überladene proceduren machen?
denn
type TFeld=class
zeichnen: TMeineProzedurenMitSpeziellenParameter;
zeichnen: TMeineProzedurenMitSpeziellenParameter1; overload;
...
denn sonst kann ich ja der prozedure zeichnen keine "verschieden parameterhaltige" proceduren zuweisen
Edit: die Parameter von zeichnen sind ja auch konstant ! daher brauch ich auch eigentlich kein parameterhaltigen Prozeduren;
jfheins - Di 02.04.13 17:47
IhopeonlyReader hat folgendes geschrieben : |
Das Problem: dann ist, wenn man ein Object vom Typ TMap erstellt und dann Map.zeichnen aufruft, leider das ganze Schiefläuft, da die Klasse TMap auf das allgemeine TFeld zurückgreift... |
hast du dich schonmal intensiver mit Vererbung auseinander gesetzt? Wenn die Methoden korrekt überschrieben sind und es sich tatsächlich um ein TGrasFeld handelt (um beim Beispiel zu bleiben) wird auch von TMap die korrekte Methode TGrasFeld.zeichnen() aufgerufen.
IhopeonlyReader - Di 02.04.13 18:32
wenn ich also
var Map: TMap;
deklariere und ich dann
Map := TMap.Create; und dann
Map.Feld[C,C1] := TGrasFeld.Create;
dann ist Map.Feld richtig, allerdings ! wollte ich eigentlich bei TMaps im Construktor folgendes aufrufen:
Feld[C,C1] := TFeld.Create;
(C und C1 soll heißen For C:=0 to High(Feld) do C1:=0 to High(Feld[C] do )
also heißt das, dass ich die Felder nicht in der Klasse TMap erstellen kann ?!, da TMap ja nicht TGrasFeld kennt, sondern nur TFeld
Quitzlinga - Mi 03.04.13 09:16
Hi,
ich kann mich den Antworten nur anschliessen. Dein Problem ist ein Paradebeispiel für Vererbung und Objektorientierung.
Da man aus Beispielen aber im allgemeinen mehr lernt, habe ich mal versucht, es abzubilden
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92: 93: 94: 95: 96: 97: 98: 99: 100: 101: 102: 103: 104: 105: 106: 107: 108: 109: 110: 111: 112: 113: 114: 115: 116: 117: 118: 119: 120: 121: 122: 123: 124: 125: 126: 127: 128: 129: 130: 131: 132: 133: 134: 135: 136: 137: 138: 139: 140: 141: 142: 143: 144: 145: 146: 147: 148: 149: 150: 151: 152: 153: 154: 155: 156: 157: 158: 159: 160: 161: 162: 163: 164: 165: 166: 167: 168: 169: 170: 171: 172: 173: 174: 175: 176: 177: 178: 179: 180: 181: 182: 183:
| unit uMapVerwaltung;
interface
uses Graphics;
type TFeldType = (ftGras, ftSteppe, ftWasser);
type TFeld = class(TObject) private procedure Zeichnen(x, y : integer; aCanvas : TCanvas);virtual;abstract; public procedure Betreten();virtual;abstract; procedure Verlassen();virtual;abstract; end;
type TGrasFeld = class(TFeld) private procedure Zeichnen(x, y : integer; aCanvas : TCanvas);override; public procedure Betreten();override; procedure Verlassen();override; end;
type TSteppeFeld = class(TGrasFeld) private procedure Zeichnen(x, y : integer; aCanvas : TCanvas);override; public procedure Betreten();override; procedure Verlassen();override; end;
type TWasserFeld = class(TFeld) private procedure Zeichnen(x, y : integer; aCanvas : TCanvas);override; public procedure Betreten();override; procedure Verlassen();override; end;
type TMapArray = Array of Array of TFeld; type TMap = class(TObject) private fMap : TMapArray; fLinkCanvas : TCanvas; procedure Init(x, y : integer); procedure Setze(x, y : integer; aFeldType : TFeldType); public constructor Create(); destructor Destroy(); procedure Betrete(x, y : integer); procedure Verlasse(x, y : integer); procedure Zeichne();overload; procedure Zeichne(x,y : integer);overload; property Canvas : TCanvas read fLinkCanvas write fLinkCanvas; end;
implementation
uses SysUtils, Dialogs;
procedure TGrasFeld.Zeichnen(x, y : integer; aCanvas : TCanvas); begin ShowMessage('Zeichne Gras'); end;
procedure TGrasFeld.Betreten(); begin ShowMessage('Betrete Gras'); end;
procedure TGrasFeld.Verlassen(); begin ShowMessage('Verlasse Gras'); end; procedure TSteppeFeld.Zeichnen(x, y : integer; aCanvas : TCanvas); begin inherited Zeichnen(x, y, aCanvas); ShowMessage('Zeichne zusätzlich Steine'); end;
procedure TSteppeFeld.Betreten(); begin inherited Betreten(); end;
procedure TSteppeFeld.Verlassen(); begin inherited Verlassen(); end; procedure TWasserFeld.Zeichnen(x, y : integer; aCanvas : TCanvas); begin ShowMessage('Zeichne Wasser'); end;
procedure TWasserFeld.Betreten(); begin ShowMessage('Betrete Wasser'); end;
procedure TWasserFeld.Verlassen(); begin ShowMessage('Verlasse Wasser'); end; constructor TMap.Create(); begin Init(20,20); end;
destructor TMap.Destroy(); var i, j : integer; begin for i := Low(fMap) to High(fMap) do begin for j := Low(fMap[i]) to High(fMap[i]) do begin FreeAndNil(fMap[i,j]); end; end; end;
procedure TMap.Init(x, y : integer); var i,j : integer; begin SetLength(fMap, x); for i := Low(fMap) to High(fMap) do SetLength(fMap[i], y);
for i := Low(fMap) to High(fMap) do begin for j := Low(fMap[i]) to High(fMap[i]) do begin fMap[i,j] := NIL; end; end;
end;
procedure TMap.Setze(x, y : integer; aFeldType : TFeldType); begin FreeAndNil(fMap[x,y]); case aFeldType of ftGras : fMap[x,y] := TGrasFeld.Create(); ftSteppe : fMap[x,y] := TSteppeFeld.Create(); ftWasser : fMap[x,y] := TWasserFeld.Create(); end; Zeichne(x, y); end;
procedure TMap.Zeichne(); var i,j : integer; begin for i := Low(fMap) to High(fMap) do begin for j := Low(fMap[i]) to High(fMap[i]) do begin fMap[i,j].Zeichnen(i, j, fLinkCanvas); end; end; end;
procedure TMap.Zeichne(x, y : integer); begin fMap[y,x].Zeichnen(x, y, fLinkCanvas); end;
procedure TMap.Betrete(x, y : integer); begin if fMap[x,y] <> NIL then fMap[x,y].Betreten(); end;
procedure TMap.Verlasse(x, y : integer); begin if fMap[x,y] <> NIL then fMap[x,y].Verlassen(); end;
end. |
Das ganze müsste den Sachverhalt von Dir recht gut abbilden. Wie Du sehen kannst, kannst Du auch ohne Änderungen zur Laufzeit individuelle Aufrufe pro Objekt machen. Individuelle Anpassungen der Routinen zur Laufzeit sind ohnehin keine gute Idee, da Du irgentwann den Überblick verlierst und das Debugging in einen solchen Fall sehr schwer ist.
Das ganze ist ungetestet aber vom Grundsatz müsste es stimmen.
MfG
Quitzlinga
IhopeonlyReader - Mi 03.04.13 13:23
ich kenne solche Vererbung klar, aber ich habe eigentlich versucht diese zu vermeiden, da ich verschiedene Parameter immer habe, gras zeichnen muss ich nur grasfarbe angeben, bei steppe gras und steinfarbe als Beispiel...
dann müsste ich alle unterschiede ins create Ereignis packen oder?
Gausi - Mi 03.04.13 13:55
Dann nimm die Parameter aus der Zeichnen-Funktion raus und nutze dafür Felder der Klasse, die nach dem Create entsprechend gesetzt werden. Wenn ein Feld erstmal vorhanden ist, dann ändert sich das Feld ja nicht ständig, so dass man der zeichnen-Funktion ständig diese Parameter mitgeben muss, oder?
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2025 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!