Entwickler-Ecke

Multimedia / Grafik - Auf Klassenfremdes Canvas zugereifen


FinnO - Do 12.03.09 19:19
Titel: Auf Klassenfremdes Canvas zugereifen
Hi Community,

Im Informatikunterricht programmieren ein Kumpel und ich gerade eine neue, für unsere Zwecke verbesserte Turtle-Komponente.

Dazu würden wir gerne das Canvas, auf das gezeichnet werden soll variabel machen. Leider hagelt es bei ungefähr folgendem Code dauernd Zugriffsverletzungen


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
...
property ZielCanvas : TCanvas read GetCanvas write Setcanvas;
...
begin
  ZielCanvas := Image.Canvas;
end;


begin
  ZielCanvas.doSth
end;


muss man das evtl. Anders angehen?


Christian S. - Do 12.03.09 19:55

Ich fürchte, Hilfe wird hier schwer fallen. Du hast nicht gesagt, welche Fehler gemeldet werden und der Quelltext erscheint völlig aus dem Zusammenhang gerissen und entscheidende Teile (z.B. Getter- und Setter-Methoden) fehlen.


ub60 - Do 12.03.09 20:08

Bei dem geringen Quelltext nur eine Vermutung.
Also zuerst einmal, man kann´die Canvas zuweisen. Irgendwie sollte es dann aber

Delphi-Quelltext
1:
Zielcanvas=FCanvas                    

oder so heißen, Du übergibst ja nicht das Image.

ub60


FinnO - Do 12.03.09 21:59

Sorry, ich kann den Code aus der Schule leider nicht mehr wortwörtlich aber im Groben ist das so aufgebaut:

ich glaube, das canvas war eine Field...

Delphi-Quelltext
1:
  FZielCanvas : TCanvas;                    


Gesetzt wird das ganze so:


Delphi-Quelltext
1:
  FZielCanvas := Image1.Canvas                    


Die Idee dahinter ist, dass nun die Änderungen die wir an der ZielCanvas vornehmen sich auf die Image1.Canvas auswirken.

(ich glaube hier haben wir einen Denkfehler gemacht, muss man da mit Pointern o.ä. Arbeiten? Oder mit Handles (KP), weil ich glaube, so wie es momentan ist, werden die Änderungen nur in der ZielCanvas geändert nicht aber auf der eigentlich zu benutzenden Canvas Image1.Canvas?)

der Versuch zu Zeichnen ist dann

Delphi-Quelltext
1:
 FZielCanvas.LineTo(X,Y);                    


und so weiter.


Yogu - Do 12.03.09 22:07

user profile iconFinnO hat folgendes geschrieben Zum zitierten Posting springen:

Delphi-Quelltext
1:
  FZielCanvas := Image1.Canvas                    

Was ist Image1? Wo wird das gesetzt? Und warum glaubst du, dass die Änderungen an FZielCanvas durchgeführt werden? Ein Canvas alleine ist nichts - du kannst ihn nicht einfach erzeugen, also muss er wohl der zugewiesene sein. Andernfalls würde eine Exception ausgelöst werden.


FinnO - Do 12.03.09 22:12

image1 ist eine ganz normale Komponente vom Typ TImage auf dem Formular...

Ich habe mittlerweile die Vermutung wir liegen sowas von falsch, dass ich lieber einfach mal unseren Code vergesse und die Frage in den Raum werf:

Angenommen, ich möchte ein beliebiges Bild auf irgendein beliebiges Canvas zeichnen, wie gehe ich das an? Dabei muss beachtet werden, dass ich Das Canvas variable zuweisen möchte und nicht Hardcoden.


Xentar - Do 12.03.09 22:45

Ähm.. versteh ich das richtig:
Du hast eine Klasse erstellt. In dieser Klasse möchtest du ein Canvas verwenden?
Warum greifst du dann doch wieder auf ein bestimmtes Canvas, nämlich in diesem Fall Image1.Canvas zu..?

Normalerweise geht man doch so vor, dass man beim instanziieren dieser Klasse das Canvas VON AUSSEN reinreicht, und nicht, dass sich die Klasse das selber holt?
Edit: Dafür ist ja normalerweise auch das Property, dass du bereits angelegt hast.. zeig mal mehr Code.


ub60 - Do 12.03.09 23:39

user profile iconFinnO hat folgendes geschrieben Zum zitierten Posting springen:
Die Idee dahinter ist, dass nun die Änderungen die wir an der ZielCanvas vornehmen sich auf die Image1.Canvas auswirken.
(ich glaube hier haben wir einen Denkfehler gemacht, muss man da mit Pointern o.ä. Arbeiten?

Weder noch. Die Idee ist i.O., die übergebene Canvas ist nichts anderes als ein Zeiger.
Zum Vorgehen ein Beispiel:

ub60


FinnO - Fr 13.03.09 19:14

soo ich hab das mal wie UB gesagt hat (bzw. wie ich es verstanden habe) gemacht...


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:
type
  TZeichnen = Class

    procedure SetCanvas(Canvas : TCanvas);
    function  GetCanvas : TCanvas;
    
    property FCanvas read GetCanvas write SetCanvas;
  end;

implementation

{$R *.dfm}

procedure TZeichnen.SetCanvas(Canvas : TCanvas);
begin
  FCanvas := Canvas // Reicht das hier???
end;

procedure TZeichnen.GetCanvas : TCanvas
begin
  result := FCanvas;
end;

procedure TForm1.Form1Create(Sender : TObject);
var
  Z : TZeichnen;
begin
  Z.FCanvas.Ellipse(100,100,200,200); // Zugriffsverletzung
end;


Wodran liegts?


elundril - Fr 13.03.09 19:23


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:
type
  TZeichnen = Class
  private
    FCanvas: TCanvas
  public
      procedure SetCanvas(Canvas : TCanvas);
          function  GetCanvas : TCanvas;
  published   
      property Canvas read GetCanvas write SetCanvas;
  end;

implementation

{$R *.dfm}

procedure TZeichnen.SetCanvas(Canvas : TCanvas);
begin
  FCanvas := Canvas // Reicht das hier???
end;

procedure TZeichnen.GetCanvas : TCanvas
begin
  result := FCanvas;
end;

procedure TForm1.Form1Create(Sender : TObject);
var
  Z : TZeichnen;
begin
  Z := TZeichnen.Create;
  Z.Canvas := TForm1.Canvas;
  Z.Canvas.Ellipse(100,100,200,200); // Zugriffsverletzung
end;


so sollte es schon eher funktionieren denke ich.

lg elundril


Marc. - Fr 13.03.09 19:24


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
procedure TForm1.Form1Create(Sender : TObject);
var
  Z : TZeichnen;
begin
  Z.SetCanvas(...);
  Z.FCanvas.Ellipse(100,100,200,200);
end;


IMHO solltest du auch die Setter Methode aufrufen, bevor du auf ein nicht referenziertes Canvas zugreifst. ;)


FinnO - Fr 13.03.09 19:25

@ elundril: negativ :(

@Marc. + Elundril: Kombiniert klappts, beim Beenden kriege ich noch folgende Exception:

"Externe Exception"


ub60 - Fr 13.03.09 20:22

Was ich meinte, geht etwa so:

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:
type
  TZeichnen = Class
    protected
      FCanvas : TCanvas;
    public
      procedure SetCanvas(Canvas : TCanvas);
      procedure ZeichneKreis(x,y,r:Integer);
      function  GetCanvas : TCanvas;
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

function TZeichnen.GetCanvas: TCanvas;
begin
  Result:=FCanvas;
end;

procedure TZeichnen.SetCanvas(Canvas : TCanvas);
begin
  FCanvas := Canvas;
end;

procedure TZeichnen.ZeichneKreis(x,y,r:Integer);
begin
  FCanvas.Ellipse(x-r, y-r, x+r, y+r);
end;

procedure TForm1.FormCreate(Sender : TObject);
var Z : TZeichnen;
begin
  Z:=TZeichnen.Create;
  Z.SetCanvas(Image1.Canvas);
  Z.ZeichneKreis(10015050);
  Z.Free;
end;

ub60


Xentar - Fr 13.03.09 21:03

user profile iconub60 hat folgendes geschrieben Zum zitierten Posting springen:
Was ich meinte, geht etwa so:

Delphi-Quelltext
1:
2:
3:
    public
      procedure SetCanvas(Canvas : TCanvas);
      function  GetCanvas : TCanvas;


Genau das macht doch ein Property - nur eben als eine Eigenschaft.


Yogu - Fr 13.03.09 22:02

Äh, jetzt nochmal im Klartext: Die Zugirffsverletzung kam, weil das Objekt Z (übrigens ein sehr gut gewählter Bezeichner für eine Zeichenklasse ;)) nicht initialisiert wurde. user profile iconub60 hat die fehlende Zeile in seinem Code eingeführt.

Aber so, wie die Klasse bis jetzt definiert ist, könnte man noch einiges rausschmeißen:




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:
type
  TZeichnen = class
  private
    fCanvas: TCanvas;
  public
    procedure ZeichneKreis(x, y, r: Integer);

    property Canvas: TCanvas read fCanvas write fCanvas;
  end;

implementation

procedure TZeichnen.ZeichneKreis(x, y, r: Integer);
begin
  fCanvas.Ellipse(x-r, y-r, x+r, y+r);
end;

procedure TForm1.FormCreate(Sender : TObject);
var Zeichner : TZeichnen;
begin
  Zeichner := TZeichnen.Create;
  try
    Zeichner.SetCanvas(Image1.Canvas);
    Zeichner.ZeichneKreis(10015050);
  finally
    Zeichner.Free;
  end;
end;


FinnO - Sa 14.03.09 00:23

hmm also ersteres war klar ^^

zweiteres Wusste ich gar nicht :oops:

aber jetzt ist alles Klärchen... danke


Ich geb euch doch nicht den Code von meiner Turtle ;) da muss schon mal ne Zeichenklasse Z zur verdeutlichung herhalten :evil:

:closed: