Autor |
Beitrag |
IhopeonlyReader
      
Beiträge: 600
Erhaltene Danke: 23
Delphi 7 PE
|
Verfasst: Di 02.04.13 15:23
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?
_________________ Sucht "neueres" Delphi
Wer nicht brauch was er hat, brauch auch nicht was er nicht hat!
|
|
Perlsau
Ehemaliges Mitglied
Erhaltene Danke: 1
|
Verfasst: 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 
      
Beiträge: 600
Erhaltene Danke: 23
Delphi 7 PE
|
Verfasst: Di 02.04.13 15:59
Perlsau hat folgendes geschrieben : | Und wozu soll das gut sein? |
Um allgemin gültige Typen zu schreiben
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
_________________ Sucht "neueres" Delphi
Wer nicht brauch was er hat, brauch auch nicht was er nicht hat!
|
|
jfheins
      
Beiträge: 918
Erhaltene Danke: 158
Win 10
VS 2013, VS2015
|
Verfasst: 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
      
Beiträge: 8548
Erhaltene Danke: 477
Windows 7, Windows 10
D7 PE, Delphi XE3 Prof, Delphi 10.3 CE
|
Verfasst: 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; |
_________________ We are, we were and will not be.
|
|
IhopeonlyReader 
      
Beiträge: 600
Erhaltene Danke: 23
Delphi 7 PE
|
Verfasst: 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;
_________________ Sucht "neueres" Delphi
Wer nicht brauch was er hat, brauch auch nicht was er nicht hat!
|
|
jfheins
      
Beiträge: 918
Erhaltene Danke: 158
Win 10
VS 2013, VS2015
|
Verfasst: 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 
      
Beiträge: 600
Erhaltene Danke: 23
Delphi 7 PE
|
Verfasst: 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
_________________ Sucht "neueres" Delphi
Wer nicht brauch was er hat, brauch auch nicht was er nicht hat!
|
|
Quitzlinga
      
Beiträge: 60
Erhaltene Danke: 2
Win XP
Delphi 2007 Prof. Codegear Win32
|
Verfasst: 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
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 
      
Beiträge: 600
Erhaltene Danke: 23
Delphi 7 PE
|
Verfasst: 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?
_________________ Sucht "neueres" Delphi
Wer nicht brauch was er hat, brauch auch nicht was er nicht hat!
|
|
Gausi
      
Beiträge: 8548
Erhaltene Danke: 477
Windows 7, Windows 10
D7 PE, Delphi XE3 Prof, Delphi 10.3 CE
|
Verfasst: 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?
_________________ We are, we were and will not be.
|
|
|