Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   GUI-Design mit VCL / FireMonkey / Common Controls (https://www.delphipraxis.net/18-gui-design-mit-vcl-firemonkey-common-controls/)
-   -   Delphi Abgel. graf. Komponente aktualisiert nicht (https://www.delphipraxis.net/51571-abgel-graf-komponente-aktualisiert-nicht.html)

leddl 15. Aug 2005 11:09


Abgel. graf. Komponente aktualisiert nicht
 
Servus Leute,

nach längerer Zeit habe ich mich dann nun auch endlich mal wieder ans Programmieren rangewagt und stehe sofort vor einem - eher kleinen, aber dennoch nervigen - Problem.
Ich versuche gerade, ein Kartenspiel zu programmieren und habe mir für diesen Zweck eine Klasse TCustomCard von TGraphicControl abgeleitet, von der ich wiederrum die 3 verschiedenen Kartentypen (Karten mit Zahlen von 1-12 in 4 Farben, Joker, Aussetzen) ableite. Die Basisklasse besitzt so gut wie keine Eigenschaften und Funktionen, insofern hätte ich das ganze auch anders lösen können. Ich empfand es aber als gute Möglichkeit, mal den Umgang mit Vererbung etwas näher kennen zu lernen.
Die Basisklasse besitzt die Eigenschaft CardOpen : Boolean, die besagt, ob die Karte offen oder verdeckt liegt.
Meine zugehörige setter-Methode sieht aus wie folgt:
Delphi-Quellcode:
procedure TCustomCard.setCardOpen(aCardOpen : Boolean);
Begin
  if aCardOpen <> fCardOpen Then
  Begin
    fCardOpen := aCardOpen;
    Paint;
  End;
End;
Die Paint-Methode habe ich erst in den abgeleiteten Klassen implementiert, weil erst dort Daten vorhanden sind, über die ich die Oberfläche bestimme. Dennoch sollte doch - meinem Verständnis der Vererbung nach - bei einem Ändern der Eigenschaft in einer abgeleiteten Klasse auch die entsprechende Paint-Methode der abgeleiteten Klasse aufgerufen werden, und nicht die der Basisklasse, oder? Das scheint nämlich hier nicht der Fall zu sein. Die Oberfläche wird nämlich nicht neu gezeichnet. Erst durch eine Extra-Funktion in der abgeleiteten Klasse aktualisiert sich die Ansicht. :(

Und ne kleine zweite Frage hätte ich auch noch kurz. Ich weiß, "neue Frage, neuer Thread", aber die Frage is eigentlich so klein, daß sich ein Thread nicht lohnt. ;)
Kann ich - der Einfachheit halber - diese abgeleiteten Klassen später dennoch als TCustomCard deklarieren, und dann per Typenüberprüfung darauf zugreifen? Das könnte mir später eventuell etwas Arbeit ersparen.

Phistev 15. Aug 2005 12:46

Re: Abgel. graf. Komponente aktualisiert nicht
 
zu 2.: Ja, kannst du, das nennt sich Polymorphie

zu 1.: Wie ist TCustomCard.Paint deklariert? Empfehlenswert wäre
Delphi-Quellcode:
procedure Paint; virtual; abstract;

leddl 15. Aug 2005 13:00

Re: Abgel. graf. Komponente aktualisiert nicht
 
Zitat:

Zitat von Phistev
zu 2.: Ja, kannst du, das nennt sich Polymorphie

OK, dann muß ich da aber auch nichts ändern, das geht einfach so?
Zitat:

Zitat von Phistev
zu 1.: Wie ist TCustomCard.Paint deklariert? Empfehlenswert wäre
Delphi-Quellcode:
procedure Paint; virtual; abstract;

Bisher habe ich es nur mit override deklariert und nur die übergeordnete Paint-Methode aufgerufen. Aber das könnte ich eigentlich auch wieder entfernen, da Paint wie gesagt erst in den abgeleiteten Klassen eine Bedeutung bekommt. Aber das mit virtual und abstract werde ich mal austesten. Kann dazu dann leider erst morgen was sagen, da ich hier auf der Arbeit kein Delphi und daheim keinen Internetanschluß habe :roll:

Robert_G 15. Aug 2005 15:33

Re: Abgel. graf. Komponente aktualisiert nicht
 
Delphi-Quellcode:
type TBase = class
  protected
    procedure Paint; virtual; abstract;
  public
    procedure DoSomething;
  end;
Delphi-Quellcode:
type
  Descendant1 = class(Base)
  protected
    procedure Paint; override;
  end;

  Descendant2 = class(Base)
  protected
    procedure Paint; override;
  end;
Wenn du in einer Mehtode in Base nun Paint aufrufst wird die Implementierung der Ableitung benutzt.

Zur Frage nach der Polymorphy:
Delphi-Quellcode:
var
  Instance1, Instance2 :Base;
begin
  Instance1 := Descendant1.Create();
  Instance2 := Descendant2.Create();
Instance1 & Instance2 lassen sich somit auf die Methoden von Base zusammenfassen und gleich behandeln, sie zeichnen sich aber unterschiedlich. ;)

leddl 15. Aug 2005 15:42

Re: Abgel. graf. Komponente aktualisiert nicht
 
OK, danke für die erklärende Zusammenfassung. Werd ich mir zu Gemüte führen und später dann mal testen. Und dann mal schaun, wie weit ich komme, wenn ich damit dann die einzelnen Karten fertig hab. Jetzt fängts nämlich erst so richtig an :lol:

leddl 16. Aug 2005 08:51

Re: Abgel. graf. Komponente aktualisiert nicht
 
Mist, jetzt sehe ich gerade, daß Robert noch override hinter die Paint-Methoden der abgeleiteten Klassen gepackt hat. :wall:
Ich meine aber, daß das bei mir nicht ging. Am Anfang müsste es nämlich so gewesen sein, weil ich vergessen hatte, es rauszunehmen, als ich virtual und abstract hinzugefügt hatte.
Das ging aber, soweit ich mich erinnere nicht, weil die Paint-Methode in der Basisklasse nicht implementiert war. Habe ich sie dann implementiert, krieg ich einen Abstract Error. Klar, kann ja nich ne abstrakte Methode doch noch implementieren.
So, dann hab ich das override und die Implementierung in der Basisklasse rausgenommen. Dann wurde auch brav compiliert. Beim Setzen von CardOpen (ihr erinnert euch, die setter-Methode aus meinem ersten Beitrag ;)) bekomme ich allerdings wieder einen Abstract Error. Warum?

OK, davon jetzt mal abgesehen. Seit dem Ändern habe ich noch ein ganz anderes Problem bekommen: Die Paint-Methoden der abgeleiteten Klassen funktioniert nicht mehr richtig, seit ich das "inherited Paint" entfernt habe, daß mir ja nur Fehler gebracht hat, seit ich Paint als abstract deklariert hatte. Jetzt wird nämlich nicht neugezeichnet, wenn ich Paint aufrufe, es sei denn, ich rufe in der Paint-Methode zB als erstes ein ShowMessage auf. Kann mir das mal jemand erklären? :gruebel:

//Edit:
Ich pack jetzt einfach mal den relevanten Teil meines bisherigen Quellcodes rein, dann is es vielleicht einfacher, mir das näher zu bringen ;)
Delphi-Quellcode:
unit UCard;

interface

uses
  SysUtils, Classes, Controls, Graphics;

type
  TCardValue = (CVblue_01, CVblue_02, CVblue_03, CVblue_04, CVblue_05, CVblue_06,
                CVblue_07, CVblue_08, CVblue_09, CVblue_10, CVblue_11, CVblue_12,
                CVyellow_01, CVyellow_02, CVyellow_03, CVyellow_04, CVyellow_05, CVyellow_06,
                CVyellow_07, CVyellow_08, CVyellow_09, CVyellow_10, CVyellow_11, CVyellow_12,
                CVgreen_01, CVgreen_02, CVgreen_03, CVgreen_04, CVgreen_05, CVgreen_06,
                CVgreen_07, CVgreen_08, CVgreen_09, CVgreen_10, CVgreen_11, CVgreen_12,
                CVred_01, CVred_02, CVred_03, CVred_04, CVred_05, CVred_06,
                CVred_07, CVred_08, CVred_09, CVred_10, CVred_11, CVred_12);
type
  TCustomCard = class(TGraphicControl)
  private
    { Private declarations }
    fCardOpen : Boolean;
    fImageDirectory, fCardImagePath : String;
    fCardImage : TBitmap;

    const CardFileNames : Array[0..50] of String =
            ('blue_01.bmp','blue_02.bmp','blue_03.bmp','blue_04.bmp','blue_05.bmp','blue_06.bmp',
            'blue_07.bmp','blue_08.bmp','blue_09.bmp','blue_10.bmp','blue_11.bmp','blue_12.bmp',
            'yellow_01.bmp','yellow_02.bmp','yellow_03.bmp','yellow_04.bmp','yellow_05.bmp','yellow_06.bmp',
            'yellow_07.bmp','yellow_08.bmp','yellow_09.bmp','yellow_10.bmp','yellow_11.bmp','yellow_12.bmp',
            'green_01.bmp','green_02.bmp','green_03.bmp','green_04.bmp','green_05.bmp','green_06.bmp',
            'green_07.bmp','green_08.bmp','green_09.bmp','green_10.bmp','green_11.bmp','green_12.bmp',
            'red_01.bmp','red_02.bmp','red_03.bmp','red_04.bmp','red_05.bmp','red_06.bmp',
            'red_07.bmp','red_08.bmp','red_09.bmp','red_10.bmp','red_11.bmp.bmp','red_12.bmp',
            'joker.bmp','next_player.bmp','backside.bmp');

    procedure setCardOpen(aCardOpen : Boolean);

  protected
    { Protected declarations }
    procedure Paint; virtual; abstract;

  public
    { Public declarations }
    property CardOpen : Boolean read fCardOpen write setCardOpen;
    property ImageDirectory : String read fImageDirectory;

    constructor Create(aOwner : TComponent); override;
    destructor Destroy; override;

  published
    { Published declarations }
end;

type
  TCard = class(TCustomCard)
  private
  { Private declarations }
    fCardValue : TCardValue;

  protected
    { Protected declarations }
    procedure Paint;

  public
    { Public declarations }
    property CardValue : TCardValue read fCardValue;

    procedure Initialize(aImageDirectory : String; aCardValue : TCardValue; aCardOpen : Boolean = false);

  published
    { Published declarations }
end;

implementation

{
********************************************************************************
***********************************CUSTOMCARD***********************************
********************************************************************************
}

procedure TCustomCard.setCardOpen(aCardOpen : Boolean);
Begin
  if aCardOpen <> fCardOpen Then
  Begin
    fCardOpen := aCardOpen;
    Paint;
  End;
End;

constructor TCustomCard.Create(aOwner : TComponent);
Begin
  inherited Create(aOwner);
  Width := 57;
  Height := 86;
  fCardImage := TBitmap.Create;
End;

destructor TCustomCard.Destroy;
Begin
  FreeAndNil(fCardImage);

  inherited Destroy;
End;



{
********************************************************************************
**************************************CARD**************************************
********************************************************************************
}

procedure TCard.Paint;
Begin
  fCardImage.LoadFromFile(fCardImagePath);
  Canvas.Draw(0,0,fCardImage);
End;

procedure TCard.Initialize(aImageDirectory : String; aCardValue : TCardValue; aCardOpen : Boolean = false);
Begin
  If aImageDirectory <> fImageDirectory Then
    fImageDirectory := IncludeTrailingBackslash(aImageDIrectory);
  If aCardValue <> fCardValue Then
    fCardValue := aCardValue;
  If aCardOpen <> fCardOpen Then
    fCardOpen := aCardOpen;
   
  If fCardOpen Then
    fCardImagePath := fImageDirectory + CardFileNames[Integer(fCardValue)]
  Else
    fCardImagePath := fImageDirectory + CardFileNames[50];

  Paint;
End;

Robert_G 16. Aug 2005 09:11

Re: Abgel. graf. Komponente aktualisiert nicht
 
Du hast jetzt 2-mal Paint. Einmal von der Basisklasse und einmal von der Ableitung.
Wenn du eine abstrakte Methode überschreibst darfst du natürlich NICHT inherited aufrufen.
Ist ja auch gar nix da, was im Vorgänger aufgerufen werden könnte -> *abstract error*.
Wie kamst du eigentlich auf die Idee mit dem inherited? :gruebel:

leddl 16. Aug 2005 09:18

Re: Abgel. graf. Komponente aktualisiert nicht
 
Weil ich vorher eben keine abstrakte Basismethode hatte ;) Da war das inherited noch ein Überbleibsel. Allerdings hats ja - soweit ich mich erinnere - mit dem override auch nicht hingehauen, solange ich keine Paint-Methode in der Basisklasse implementiert hatte - da hat danna ber natürlich wieder das abstract zugehauen. ;)
Problem is aber grade, daß ich eben hier kein Delphi habe, und daher nur aus dem Gedächtnis erzählen kann. Vielleicht lieg ich auch irgendwo mal falsch.

Könntest du mir gerade an meinem Code mal zeigen, wie ich das zum Laufen bekomme?

jfheins 16. Aug 2005 10:35

Re: Abgel. graf. Komponente aktualisiert nicht
 
Also, so funktioniert es:
Delphi-Quellcode:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure FormCreate(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
   end;

   TKlasse = class(TGraphicControl)
   public
      procedure DoSomething;
   end;

   TErbe1 = class(TKlasse)
   protected
      procedure Paint; override;
   end;

   TErbe2 = class(TKlasse)
   protected
      procedure Paint; override;
   end;


var
   Form1: TForm1;
   Klasse: TKlasse;

implementation

{$R *.dfm}

{ TKlasse }

procedure TKlasse.DoSomething;
begin
   Paint;
end;

{ TErbe1 }

procedure TErbe1.Paint;
begin
  inherited;

   with Canvas do
   begin
      Brush.Color := clRed;
      Rectangle(10, 10, 80, 80);
   end;

end;

{ TErbe2 }

procedure TErbe2.Paint;
begin
  inherited;

   with Canvas do
   begin
      Brush.Color := clGreen;
      Ellipse(10, 10, 80, 80);
   end;

end;

procedure TForm1.FormCreate(Sender: TObject);
begin
 Klasse := TErbe1.Create(Self);

   with Klasse do
   begin
      Parent := Self;
      Top := 50;
      Left := 50;
      Height := 100;
      Width := 100;
   end;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
Klasse.DoSomething;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
   Klasse.Free;
end;

end.
;)

leddl 16. Aug 2005 11:01

Re: Abgel. graf. Komponente aktualisiert nicht
 
Also wenn das so funktioniert, dann möchte ich mal gerne wissen, was dann an meiner Setter-Methode so anders ist, daß es bei mir nicht funktioniert.
Naja, nichtsdestotrotz bin ich jetzt heiß darauf zu erfahren, wie ich es denn jetzt mit der abstrakten Methode zum Laufen bekomme. Sagt mal was...

Robert_G 16. Aug 2005 11:32

Re: Abgel. graf. Komponente aktualisiert nicht
 
nooochmaaal zum Mitschreiben...
override klappt nur mit Methoden, die als virtual oder dynamic deklariert sind.
Eine abstrakte Methode ist virtuell, aber sie enthält keine Implementierung. (Ich habe absolut KEINE Ahnung, warum man das virtual davor schreiben muss :wall: )
Wenn du für verschiedene Ableitungen unetrschiedliches Verhalten haben willst, dass du auf einen gleichen Satz von Methoden/PRoperties zusammenfassen kannst *musst* du virtuelle Methoden nehmen.

Delphi-Quellcode:
Base = class
  procedure Paint; virtual; abstract;
  procedure DoSomething;
end;
du hattest:
Delphi-Quellcode:
Descendant = class(Base)
  procedure Paint;
end;
Was ist falsch?
Du hast eine neue Methode Namens Paint eingeführt, anstatt Base.Paint zu implementieren.
Delphi-Quellcode:
var
  Instance : Descendant;
begin
  Instance.Paint();
  Base(Instance).Paint();
Das sind zwei unterschiedliche Methoden, Erstere gibt dir den abstract error, da sie nix hat, was sie ausführen könnte.
Bist du innerhalb von Base greifst du also auf die Methode zu, von der du verlangst, dass sie der Nachfolger implementiert:
Delphi-Quellcode:
procedure Base.DoSomething;
begin
  Paint();
end;
Sollte also klar sein warum es knallt. ;)

Zweiter Fehler, den du vllt gemacht hast:
Delphi-Quellcode:
procedure Descendant.Paint;
begin
  inherited;
Damit zwingst du einen Call direkt auf die abstrakte Methode von Base -> *boom* :)

Also kurz und knapp:
a) überschreibe die Methode
b) kein inherited (ist ja sowieso nix zum Aufrufen da ;) )

btw: Du willst nicht wirklich bei jedem Zeichnen das Bild von der HDD laden, oder? :shock:

jfheins 16. Aug 2005 12:03

Re: Abgel. graf. Komponente aktualisiert nicht
 
Wir haben in diesem Fall aber bereits eine virtuelle, nicht abstrakte Methode Paint des Basistyps TGraphicControl, um die wir uns in unserer Basisklasse (TKlasse/TBase/TCustomCard) gar nicht kümmern (müssen), da wir das unseren Nachfolgern überlassen.

Wenn wir nun eine Instanz der Basisklasse erzeigen, greift diese auf TGraphicCotrol.Paint zu, die nichts tut. Wenn wir in einem Nachfolger von der Basisklasse (TKlasse/TBase/TCustomCard) die paint-Methode überschreiben, dann wird auch in DoSomething (in Basisklasse (TKlasse/TBase/TCustomCard) implementiert; ruft Paint auf) die Paint-Methode des Nachfolgers aufgerufen.

Alles Klar ?

@_G also nix mit abstrakt & Co ;-)

leddl 16. Aug 2005 13:25

Re: Abgel. graf. Komponente aktualisiert nicht
 
Jungs, ihr 2 verwirrt mich gerade konkret. :stupid:
Abstrakt oder nicht abstrakt, das ist hier die Frage. :mrgreen:

Um das jetzt nochmal zusammenzufassen: Ich deklariere Paint in der Basisklasse als abstract und virtual, implementiere sie aber nicht. Dann deklariere ich in den jeweiligen Nachkommen Paint mit override, rufe aber nicht inherited auf (klar, es gibt ja keine inherited Paint)
Nun sollte auch in den Methoden der Basisklasse bei einem Aufruf von Paint die implementierte Paint des jeweiligen Nachfolgers aufgerufen werden.
Stimmt das soweit? Dann werde ich das heute abend mal austesten (Vorsichtshalber, damit ich nichts vergesse, druck ich mir das Topic mal aus :stupid:) und mich dazu morgen nochmal äußern. Falls euch ncoh ne Ergänzung dazu einfällt, meldet euch bis dreiviertel 5, ansonsten bin ich nämlich schon wech. :mrgreen:

Zitat:

Zitat von Robert_G
btw: Du willst nicht wirklich bei jedem Zeichnen das Bild von der HDD laden, oder? :shock:

Nein, das hab ich nur mal vorerst so gemacht. Das ganze ist erstmal nur ein Test gewesen, wie ich das machen muß. Da ändert sich noch einiges.

leddl 17. Aug 2005 07:52

Re: Abgel. graf. Komponente aktualisiert nicht
 
OK, danke für die Hilfe, das funktioniert jetzt wirklich. Da muß ich wohl gestern noch irgendnen Mist reingebaut haben!

Robert Marquardt 17. Aug 2005 08:44

Re: Abgel. graf. Komponente aktualisiert nicht
 
Delphi-Quellcode:
procedure TCustomCard.setCardOpen(aCardOpen : Boolean);
Begin
  if aCardOpen <> fCardOpen Then
  Begin
    fCardOpen := aCardOpen;
    Invalidate;
  End;
End;
Man ruft nicht Paint sondern Invalidate.
Invalidate markiert das Fenster als zum Neumalen vorgesehen. Windows loest daher eine WM_PAINT Nachricht aus.
Das resultiert letztlich in einem Paint-Aufruf.
Der Vorteil ist, das Windows mehrere Invalidates zusammenfasst und nur ein WM_PAINT schickt. Das bringt Speed.
setCardOpen optimiert ja schon das nur bei der Aenderung der Property ueberhaupt ein Neumalen ausgeloest wird.
Bei komplizierteren Aenderungen, bei denen mehrere Properties sich gegenseitig aendern, resultiert das in nur einem Neuzeichnen der Komponente.

leddl 17. Aug 2005 08:48

Re: Abgel. graf. Komponente aktualisiert nicht
 
OK, auch ein guter Tip. Danke dafür. Wieder was gelernt. :mrgreen:

leddl 19. Aug 2005 09:54

Re: Abgel. graf. Komponente aktualisiert nicht
 
:gruebel: Nur leider wird bei Invalidate nichts neu gezeichnet, während Paint wunderbar funktioniert...

Robert Marquardt 19. Aug 2005 11:25

Re: Abgel. graf. Komponente aktualisiert nicht
 
Dann macht du etwas falsch. Ohne aktuelle Sourcen ist das aber nicht zu beurteilen.

leddl 19. Aug 2005 11:28

Re: Abgel. graf. Komponente aktualisiert nicht
 
Sieht im Großen und Ganzen genauso aus wie weiter oben, mit den empfohlenen Änderungen. Lasse ich in der Setter-Methode Paint stehen, klappt es. Ersetze ich Paint hier durch Invalidate, wird beim Umdrehen der Karte nicht neu gezeichnet.

Robert Marquardt 19. Aug 2005 12:30

Re: Abgel. graf. Komponente aktualisiert nicht
 
"procedure Paint; override;" sollte es sein. TGraphicControl hat ja bereits eine Paint-Methode, die ueberschrieben werden soll.
Ohne override wird die Ableitungsverbindung zu TGraphicControl unterbrochen.
Bitte poste doch nochmal deinen Code, damit man ihn korrigieren und optimieren kann.

Robert_G 19. Aug 2005 12:42

Re: Abgel. graf. Komponente aktualisiert nicht
 
Zitat:

Zitat von Robert Marquardt
Ohne override wird die Ableitungsverbindung zu TGraphicControl unterbrochen.

Ich hoffte darauf, dass er selbst drauf kommt. Vor allem nachdem es auch jHeins erwähnt hatte. ;)

leddl 19. Aug 2005 12:42

Re: Abgel. graf. Komponente aktualisiert nicht
 
OK, beim Versuch, meinen vorherigen Code anzupassen, ist mir gerade eine Idee gekommen, woran es liegen könnte. Bisher lade ich das anzuzeigende Bild noch in Paint. Das wollte ich dann noch ändern, wenn der Rest funktioniert. In diesem Fall wird dann aber eben dadurch, daß das angezeigt Bild sich erst in Paint verändert natürlich auch keine Notwendigkeit erkannt, die Komponente neu zu zeichnen. Daran wirds wohl liegen. Ich teste das heute abend nochmal aus und melde mich morgen dazu nochmal.

Die Anpassungen, die du gerade noch angesprochen hast, wurden ja schon längst durch die vorherigen Posts geklärt. Das is also drin. Wird daher wohl wirklich das sein, was ich gerade geschrieben habe.

jfheins 19. Aug 2005 17:00

Re: Abgel. graf. Komponente aktualisiert nicht
 
Zitat:

Zitat von Robert Marquardt
Ohne override wird die Ableitungsverbindung zu TGraphicControl unterbrochen.

Ist das schlimm ?

TGraphicCotrol.Paint sieht etwa so aus:
Delphi-Quellcode:
procedure TGraphicCotrol.Paint;
begin
end;
Dürfte also nicht allzu viel ausmachen :mrgreen:

Robert Marquardt 19. Aug 2005 17:17

Re: Abgel. graf. Komponente aktualisiert nicht
 
Eben deshalb wird nichts angezeigt. Wenn man Invalidate aufruft, so ist das natuerlich das Invalidate von TGraphicControl.
Da Paint nicht ueberschrieben ist, wird natuerlich das Paint von TGraphicControl und nicht das neu deklarierte Paint aufgerufen.
Eine virtuelle Methode wird als Zeiger in der VMT (Virtual Method Table) abgelegt. Dort steht fuer diese Komponente erst mal das Paint von TGraphicControl.
Aufrufe von Paint gehen per Index in die VMT des Objekts.
Ueberschreibt man Paint in der abgeleiteten Konponente (override), so wird der Eintrag in der VMT durch das neue Paint ersetzt.
Damit ist eigentlich die ganze Vererbung erklaert.
dynamic macht keinen Eintrag in die VMT, stattdessen wird eine Suche nach dem Namen eingesetzt. Das Ergebnis ist das gleiche. Man tauscht nur Suchzeit gegen Speicherplatzersparnis.

Robert_G 19. Aug 2005 17:17

Re: Abgel. graf. Komponente aktualisiert nicht
 
Zitat:

Zitat von jfheins
Zitat:

Zitat von Robert Marquardt
Ohne override wird die Ableitungsverbindung zu TGraphicControl unterbrochen.

Ist das schlimm ?
...
Dürfte also nicht allzu viel ausmachen :mrgreen:

:wall:
Natürlich ist es das. Rate mal warum es das gibt? Genau, damit man generisch ein Neuzeichnen des GraphicControl-Nachfolgers auslösen kann, dieser es aber selbst implementieren kann.
Versteckt man Paint, bleibt es leer und nix passiert wenn man Paint auf die Instanz nach einem Cast auf GraphicControl ausführt.
Delphi-Quellcode:
TGraphicControl(x).Paint();
...ist dann plötzlich etwas anderes als...
Delphi-Quellcode:
X.Paint();

leddl 20. Aug 2005 16:20

Re: Abgel. graf. Komponente aktualisiert nicht
 
So, nix is. Selbst nachdem ich jetzt auch schon in der Setter-Methode das Bild gesetzt habe, wird durch Invalidate nichts nue gezeichnet. Paint funktioniert aber weiterhin wunderbar. :gruebel:
Hier mal der bisherige Code:
Delphi-Quellcode:
unit UCard;

interface

uses
  SysUtils, Classes, Controls, Graphics, Dialogs;

type
  TCardType = (CTcard, CTjoker, CTnext_player);
  TCardValue = (CVblue_01, CVblue_02, CVblue_03, CVblue_04, CVblue_05, CVblue_06,
                CVblue_07, CVblue_08, CVblue_09, CVblue_10, CVblue_11, CVblue_12,
                CVyellow_01, CVyellow_02, CVyellow_03, CVyellow_04, CVyellow_05, CVyellow_06,
                CVyellow_07, CVyellow_08, CVyellow_09, CVyellow_10, CVyellow_11, CVyellow_12,
                CVgreen_01, CVgreen_02, CVgreen_03, CVgreen_04, CVgreen_05, CVgreen_06,
                CVgreen_07, CVgreen_08, CVgreen_09, CVgreen_10, CVgreen_11, CVgreen_12,
                CVred_01, CVred_02, CVred_03, CVred_04, CVred_05, CVred_06,
                CVred_07, CVred_08, CVred_09, CVred_10, CVred_11, CVred_12);
  TJokerValue = (JVblue_01, JVblue_02, JVblue_03, JVblue_04, JVblue_05, JVblue_06,
                JVblue_07, JVblue_08, JVblue_09, JVblue_10, JVblue_11, JVblue_12,
                JVyellow_01, JVyellow_02, JVyellow_03, JVyellow_04, JVyellow_05, JVyellow_06,
                JVyellow_07, JVyellow_08, JVyellow_09, JVyellow_10, JVyellow_11, JVyellow_12,
                JVgreen_01, JVgreen_02, JVgreen_03, JVgreen_04, JVgreen_05, JVgreen_06,
                JVgreen_07, JVgreen_08, JVgreen_09, JVgreen_10, JVgreen_11, JVgreen_12,
                JVred_01, JVred_02, JVred_03, JVred_04, JVred_05, JVred_06,
                JVred_07, JVred_08, JVred_09, JVred_10, JVred_11, JVred_12,
                JVall);

type
  TCustomCard = class(TGraphicControl)
  private
    { Private declarations }
    fCardOpen : Boolean;
    fImageDirectory, fCardImagePath : String;
    fCardImage : TBitmap;

    const CardFileNames : Array[0..50] of String = ('blue_01.bmp','blue_02.bmp','blue_03.bmp','blue_04.bmp','blue_05.bmp','blue_06.bmp',
            'blue_07.bmp','blue_08.bmp','blue_09.bmp','blue_10.bmp','blue_11.bmp','blue_12.bmp',
            'yellow_01.bmp','yellow_02.bmp','yellow_03.bmp','yellow_04.bmp','yellow_05.bmp','yellow_06.bmp',
            'yellow_07.bmp','yellow_08.bmp','yellow_09.bmp','yellow_10.bmp','yellow_11.bmp','yellow_12.bmp',
            'green_01.bmp','green_02.bmp','green_03.bmp','green_04.bmp','green_05.bmp','green_06.bmp',
            'green_07.bmp','green_08.bmp','green_09.bmp','green_10.bmp','green_11.bmp','green_12.bmp',
            'red_01.bmp','red_02.bmp','red_03.bmp','red_04.bmp','red_05.bmp','red_06.bmp',
            'red_07.bmp','red_08.bmp','red_09.bmp','red_10.bmp','red_11.bmp.bmp','red_12.bmp',
            'joker.bmp','next_player.bmp','backside.bmp');

    procedure setCardOpen(aCardOpen : Boolean);

  protected
    { Protected declarations }
    procedure Paint; virtual; abstract;
    procedure SetCardImage; virtual; abstract;

  public
    { Public declarations }
    property CardOpen : Boolean read fCardOpen write setCardOpen;
    property ImageDirectory : String read fImageDirectory;

    constructor Create(aOwner : TComponent); override;
    destructor Destroy; override;

  published
    { Published declarations }
end;

type
  TCard = class(TCustomCard)
  private
  { Private declarations }
    fCardValue : TCardValue;

  protected
    { Protected declarations }
    procedure Paint; override;
    procedure SetCardImage; override;

  public
    { Public declarations }
    property CardValue : TCardValue read fCardValue;

    procedure Initialize(aImageDirectory : String; aCardValue : TCardValue; aCardOpen : Boolean = false);

  published
    { Published declarations }
end;

implementation

{
********************************************************************************
***********************************CUSTOMCARD***********************************
********************************************************************************
}

procedure TCustomCard.setCardOpen(aCardOpen : Boolean);
Begin
  if aCardOpen <> fCardOpen Then
  Begin
    fCardOpen := aCardOpen;
    SetCardImage;
    Invalidate;
  End;
End;

constructor TCustomCard.Create(aOwner : TComponent);
Begin
  inherited Create(aOwner);
  Width := 57;
  Height := 86;
  fCardImage := TBitmap.Create;
End;

destructor TCustomCard.Destroy;
Begin
  inherited Destroy;
 
  FreeAndNil(fCardImage);
End;



{
********************************************************************************
**************************************CARD**************************************
********************************************************************************
}

procedure TCard.Paint;
Begin
  Canvas.Draw(0,0,fCardImage);
End;

procedure TCard.SetCardImage;
Begin
  If fCardOpen Then
    fCardImagePath := fImageDirectory + CardFileNames[Integer(fCardValue)]
  Else
    fCardImagePath := fImageDirectory + CardFileNames[50];
   
  fCardImage.LoadFromFile(fCardImagePath);
End;

procedure TCard.Initialize(aImageDirectory : String; aCardValue : TCardValue; aCardOpen : Boolean = false);
Begin
  If aImageDirectory <> fImageDirectory Then
    fImageDirectory := IncludeTrailingBackslash(aImageDIrectory);
  If aCardValue <> fCardValue Then
    fCardValue := aCardValue;
  If aCardOpen <> fCardOpen Then
    fCardOpen := aCardOpen;

  SetCardImage;
  Invalidate;
End;

end.

Robert Marquardt 20. Aug 2005 16:34

Re: Abgel. graf. Komponente aktualisiert nicht
 
Schmeiss "procedure Paint; virtual; abstract;" raus.

Flocke 20. Aug 2005 16:35

Re: Abgel. graf. Komponente aktualisiert nicht
 
Zitat:

Zitat von leddl
Delphi-Quellcode:
...
type
  TCustomCard = class(TGraphicControl)
  ...
  protected
    { Protected declarations }
    procedure Paint; virtual; abstract; //<-- das muss weg
    procedure SetCardImage; virtual; abstract;

  ...
end;

Das "Paint; virtual; abstract;" muss weg, damit überschreibst du ja die Definition von TGraphicControl!

//EDIT: wo war die rote Box?!?

leddl 20. Aug 2005 16:44

Re: Abgel. graf. Komponente aktualisiert nicht
 
:gruebel: Wie jetzt? Wovon wird denn hier die ganze Zeit in dem Thread geredet? Mir wurde hier doch erst gesagt, ich solle das reinsetzen, damit ich jeden Nachfahren individuell zeichnen kann?

Flocke 20. Aug 2005 16:47

Re: Abgel. graf. Komponente aktualisiert nicht
 
Auszug aus Controls.pas:
Delphi-Quellcode:
  TGraphicControl = class(TControl)
  private
    FCanvas: TCanvas;
    procedure WMPaint(var Message: TWMPaint); message WM_PAINT;
  protected
    procedure Paint; virtual; //<-- HIER !!!
    property Canvas: TCanvas read FCanvas;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
  end;
Oben ist die Definition von TGraphicControl, und die hat schon eine virtuelle Methode Paint. Die musst du mit override überschreiben, aber nicht mit abstract neu definieren.

Nachtrag: und das override natürlich nur in der Klasse wo du es überschreibst.

leddl 20. Aug 2005 16:49

Re: Abgel. graf. Komponente aktualisiert nicht
 
Aha, endlich sprechen hier mal echte Experten. Robert_G? 6, setzen :mrgreen:

Naja, das test ich dann nachher gleich mal aus. Wär ja schön, wenn das endlich funktioniert.

jfheins 20. Aug 2005 23:53

Re: Abgel. graf. Komponente aktualisiert nicht
 
Zitat:

Zitat von leddl
Aha, endlich sprechen hier mal echte Experten. Robert_G? 6, setzen :mrgreen:

Zitat:

Zitat von jfheins
Wir haben in diesem Fall aber bereits eine virtuelle, nicht abstrakte Methode Paint des Basistyps TGraphicControl, um die wir uns in unserer Basisklasse (TKlasse/TBase/TCustomCard) gar nicht kümmern (müssen), da wir das unseren Nachfolgern überlassen.

Wenn wir nun eine Instanz der Basisklasse erzeigen, greift diese auf TGraphicCotrol.Paint zu, die nichts tut. Wenn wir in einem Nachfolger von der Basisklasse (TKlasse/TBase/TCustomCard) die paint-Methode überschreiben, dann wird auch in DoSomething (in Basisklasse (TKlasse/TBase/TCustomCard) implementiert; ruft Paint auf) die Paint-Methode des Nachfolgers aufgerufen.

Alles Klar ?

@_G also nix mit abstrakt & Co ;)

Bin ich jetzt auch ein Experte ? :stupid: :mrgreen:

Robert_G 21. Aug 2005 00:00

Re: Abgel. graf. Komponente aktualisiert nicht
 
Zitat:

Zitat von leddl
Aha, endlich sprechen hier mal echte Experten. Robert_G? 6, setzen :mrgreen:

Mancheiner muss das gleich 5-mal hören bevor er es einmal kapiert, nicht wahr?
Seit Seite eins predige ich, was passiert, wenn man eine ehemals virtuelle Methode neu definiert.
Da du das angefangen hast um dich mit Polymorphie zu befassen wollte ich doch nicht überall ins Detail gehen.
Manche "D'ho"s muss man sich einfach selbst an die Stirn hauen. ;)

leddl 21. Aug 2005 13:42

Re: Abgel. graf. Komponente aktualisiert nicht
 
Zitat:

Zitat von Robert_G
Mancheiner muss das gleich 5-mal hören bevor er es einmal kapiert, nicht wahr?

Du mußt es nur einmal klar un deutlich sagen, damit es auch ein Einsteiger versteht ;)
Zitat:

Seit Seite eins predige ich, was passiert, wenn man eine ehemals virtuelle Methode neu definiert.
Nur hast du mir eben dazu geraten, in meiner abgeleiteten Basisklasse Paint abstract und virtual zu deklarieren. Hättest du mir einfach gesagt "Laß Paint in CustomCard weg und deklariere in den abgeleiteten Klassen Paint mit override", dann wär das alles viel schneller erledigt gewesen :stupid:
Zitat:

Zitat von Robert_G
Da du das angefangen hast um dich mit Polymorphie zu befassen wollte ich doch nicht überall ins Detail gehen.
Manche "D'ho"s muss man sich einfach selbst an die Stirn hauen. ;)

Boah, wie gemein! :P

@jfheins:
Sorry, aber Robert hat mir das leider vor dir angefangen zu erklären, und ich hatte ihm soweit vertraut, daß er mir keinen Mist erzählt. ;)

@all:
Danke, das funktioniert jetzt wunderbar :thumb:

Robert_G 21. Aug 2005 13:54

Re: Abgel. graf. Komponente aktualisiert nicht
 
Zitat:

Zitat von leddl
Du mußt es nur einmal klar un deutlich sagen, damit es auch ein Einsteiger versteht ;)
...
Nur hast du mir eben dazu geraten, in meiner abgeleiteten Basisklasse Paint abstract und virtual zu deklarieren. Hättest du mir einfach gesagt "Laß Paint in CustomCard weg und deklariere in den abgeleiteten Klassen Paint mit override", dann wär das alles viel schneller erledigt gewesen :stupid:

Suche dir mal einen Kurs "Assoziation 101", das fehlt noch. :P
Hätte ich dir am Anfang gesagt: "Hey überschreib' einfach das Paint von GraphicControl", hättest du doch in einem halben Jahr noch keine abstrakte methode deklariert und in einer Ableitung implementiert, right? ;) Ich hätte aber nicht gedacht, dass es sich über 3 Seiten hinziehen muss... :gruebel:

leddl 21. Aug 2005 14:09

Re: Abgel. graf. Komponente aktualisiert nicht
 
Passt scho, jetzt hab ichs ja kapiert. Nur wenn einem als Anfänger in so nem Thema halt was erzählt wird, dann glaubt man das :zwinker:


Alle Zeitangaben in WEZ +1. Es ist jetzt 07:05 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