Ableitung von TCanvas/TImage

Chronix

Erfahrenes Mitglied
Irgendwie scheine ich gerade (5 Uhr nachts) ein Brett vor dem Kopf haben.. finde hier den Fehler nicht.... kann irgendwer mal nen Anstoß geben?

Gedacht ist das ganze bloß so, dass ich eine von TCanvas abgeleitete Klasse erstelle, der Ecke links oben den Mittelpunkt der Zeichenfläche als Ausgangspunkt nutzt.
Habe um ein entsprechendes Image zu haben auch gleich eine von TImage abgeleitete Klasse erstellt, die dann meine Canvas enthält.

Klassendefinitionen:
Code:
type
    TMidCanvas = class(TCanvas)
    private
        MidX, MidY : Integer;
    public
        Constructor Create( X, Y : Integer);
        procedure MoveTo( x, y : Integer);
        procedure LineTo( x, y : Integer);
end;

type TMidImage = class(TImage)
    public
        Canvas : TMidCanvas;
        constructor Create( owner: TComponent);
end;


Implementation:
Code:
Constructor TMidCanvas.Create( X, Y : Integer);
begin
inherited Create;
MidX:= x;
MidY:= y;
end;

procedure TMidCanvas.MoveTo( x, y : Integer);
begin
inherited MoveTo( MidX + x, MidY - y);
end;

procedure TMidCanvas.LineTo( x, y : Integer);
begin
inherited LineTo( MidX + x, MidY - y);
end;

constructor TMidImage.Create( owner: TComponent);
begin
inherited Create(owner);
self.Canvas:= TMidCanvas.Create( Width div 2, Height div 2);
end;



Wenn ich nun zur Laufzeit ein Image erzeuge und die Bounds gesetzt habe, kommt sobald ich darauf zeichnen möchte die Fehlermeldung ich könnte auf die Zeichenfläche nicht zeichnen.
 
Zuletzt bearbeitet:
Also spontan sehe ich erstmal nur, dass du in deiner TMidImage-Klasse als Canvas dennoch nur den normalen TCanvas und nicht deinen TMidCanvas verwendest.

Ansonsten wäre eine detaillierte Fehlermeldung und der Fehlerort (Debugger) hilfreich.
 
Hast Recht, hatte da die falsche Klasse angegeben.
Ändert trotzdem nichts am Fehler!

Beim Aufruf von TMidImage.MoveTo wird ein EInvalidOperation Fehler erzeugt.
Fehlermeldung: Leinwand/Bild erlaubt kein Zeichnen.
 
Die kurze Antwort: Deinem Canvas fehlt der Handle für den DeviceContext (HDC).
Nähere Informationen zum Device Context kannst du hier finden.
Das Standard-TImage verwendet u.a. eine TBitmap und genau diese wiederum liefert auch den HDC für ihre TCanvas-Komponente.

Dein TMidImage legt also eine Möglichkeit an, um verschiedenartig zu zeichnen (TMidCanvas:TCanvas), versäumt es dann aber, dem TMidCanvas mitzuteilen, wo seine Leinwand (also er selbst) überhaupt dargestellt werden soll.

So habe ich das zumindest nach Durchsicht diverse VCL-Sources verstanden.
 
Ahaaa, das hört sich doch sehr interessant an.
Ich dachte die Information wo das zeichnen genau zu erfolgen hat hätte TCanvas bereits durch die Übergabe von parent im Konstruktor.

Werde mich mal einlesen!
 
Ich dachte die Information wo das zeichnen genau zu erfolgen hat hätte TCanvas bereits durch die Übergabe von parent im Konstruktor.
Dachte ich auch. :) Deswegen habe ich mir mal den Spaß gegönnt und ein bißchen in den VCL-Sourcen gestöbert (Volltextsuche in Dateien sei Dank). Dabei bin ich darüber gestolpert, dass die TCanvas-Klasse u.a. ein State-Flag hat (private). Dieses gibt an, ob dem Canvas ein gültiger HDC zugeordnet wurde oder nicht. Bei allen Canvas-Operationen (wie z.B. dem MoveTo) wird vorher immer überprüft, ob dieses State-Flag durch Setzen eines HDC initialisiert wurde. Und genau das habe ich im Konstruktor vom TCanvas gefunden:
Code:
...
State := [];
Sprich: Es ist völlig egal, was du dem TCanvas bei der Initialisierung mitgibst, der State bleibt erstmal auf "ich habe keinen HDC". Der muss dann nach der Initialisierung von der entsprechenden Containerklasser (TImage, TBitmap, TSchiessmichtot) gesetzt werden.

In meinem eigenen Projekt hier verwende ich ein einziges TImage und zahlreiche TBitmaps. Das TImage dient nur als Viewport zur skalierbaren Anzeige von Bildern, sämtliche Bildmanipulationen á la TCanvas.MoveTo() laufen über TBitmaps ab, die ich dann auf die Bitmap des TImage blitte. Funktioniert bis dato ziemlich gut.
 
Sehr interessant :)
Hat was gedauert, bis ichs wieder hier gelesen habe... hatte nicht viel zeit!

Werde das mal versuchen einzubinden.

Deine Variante mit den Bitmaps halte ich bei mir nicht so für gelungen, da ich ja ansich nur alle TCanvas Zeichenfunktionen auf den Mittelpunkt eines Bildes, statt auf den linken oberen Punnkt beziehen möchte.

Das ganze soll später nen karthesisches Koordinatensystem zu realisieren, in dem mitunter auch Leute aus einem Schul-Info-Kurs halbwegs gewohnt zeichen können.
Von daher würde ich da gerne den direkten Weg gehen einfach durch ne zwischengeschaltete Klasse den Zeichenpunkt zu verschieben.

Werde mal sehen ob ich das State Flag hinbekomme ;)
 
Zurück