# SWT: wie aktualisiere ich ein Canvas zur Laufzeit?



## Guest (10. Apr 2006)

Hallo allerseits,

habe gerade mit SWT Programmierung angefangen, und bin gerade dabei mit ner Zeichenfläche (Canvas) zu arbeiten.
Mein Problem klingt ziemlich banal, aber ich hab momentan irgendwie ein Brett vorm Kopf - wahrscheinlich, weil ich noch nicht ganz nachvollzogen habe, wie das painting in SWT gehandhabt wird.

Aus AWT/Swing war ich gewohnt, dass automatisch die paint(Graphics g) Methode aufgerufen wurde. Die konnte ich mit nem repaint() auch im Nachhinein (zur Laufzeit) erneut aufrufen (bei veränderten Parametern (in dem Fall dann z.B. Attribute) wurde dann z.B. was anderes gezeichnet)

Nur bei SWT wird das ganze ja über das PaintEvent gesteuert. 
Bisher habe ich meinen Code daher nach folgendem Schema aufgebaut:

```
public class Graph extends Canvas implements PaintListener{

  public Graph(Composite parent, int style){
		super(parent, style);
		addPaintListener(this);
  }

  private void paint(PaintEvent e) {
       GC gc = e.gc;
       gc.drawString("Hello World", 50,50);
       gc.dispose();
  }	

  public void paintControl(PaintEvent e) {
	paint(e);
  }
   
}
```

Wenn ich aus ner anderen Klasse nun ein Graph Objekt erstelle, wird automatisch die paintControl() Methode aufgerufen, die dann wiederum das PaintEvent an die paint() weiterleitet.
Nur was mach ich jetzt, wenn ich zur Laufzeit noch was dazu zeichnen will? Denn in SWT gibts ja offensichtlich kein repaint(). 


*Konkrete Frage: *
_Angenommen, meine GUI wird jetzt geladen und erstellt per "new Graph(parent, style)"-Aufruf eine Zeichenfläche mit dem oben genannten "Hello World"-String an Position 50,50. Nun habe ich in der GUI noch nen Button. Wenn auf den Button geklickt wird, soll nun zusätzlich zu dem String noch mal z.B. eine Linie eingezeichnet werden. Was muss ich dazu nun in die Methode meines Actionlisteners (der auf den Button-Klick reagiert) reinschreiben?_

Ich steh grad voll auf dem Schlauch, weil ich nicht weiß, wie ich jetzt noch mal an ein PaintEvent komme, um daraus einen neuen GC zu bekommen, mit dem ich erneut was zeichnen kann...


----------



## Phil (11. Apr 2006)

Guten Morgen,

Ich hatte gestern diesen obigen Post geschrieben, und habe bisher nicht eine Antwort bekommen. Lag das bisher daran, dass einfach nur noch keiner eine Antwort wusste, oder weil ihr meine Frage nicht verstanden habt, oder etwa daran, dass meine Frage zu banal ist? Bitte gebt mir mal Feedback...

Danke euch
Phil (=Gast)


----------



## byte (11. Apr 2006)

Die meisten benutzen hier wohl kein SWT, daher kam bisher auch keine Antwort. Ich kann Dir leider auch nicht beantworten, wie man das Canvas explizit neu zeichnet. Ich weiss nur, dass man generell nur über den PaintListener zeichnen sollte, weil sonst halt das Canvas nicht korrekt neu gezeichnet wird, wenn z.B. das Fenster verschoben wird.

PS: gc.dispose() ist unnötig, weil Du den GC nicht selbst erzeugst.


Edit: Mir ist grade etwas eingefallen. Du könntest bei Bedarf einfach einen neuen PaintListener dem Canvas adden, der dann entsprechend etwas anderes zeichnet. Dazu am besten den PaintListener einfach als anonyme Klasse implementieren, z.B. so:


```
...
Canvas graph = new Canvas(parent, style)
graph.setLocation(...);
graph.setSize(...);
graph.addPaintListener(new PaintListener() {
  public void paintControl(PaintEvent e) {
    GC gc = e.gc;
    gc.drawString("Hello World", 50, 50);
  }   
});

...

//irgendwo anders dann halt
graph.addPaintListener(new PaintListener() {
  public void paintControl(PaintEvent e) {
    GC gc = e.gc;
    gc.drawString("Hello other World", 100, 100);
  }   
});
```


----------



## Phil (11. Apr 2006)

Danke dir byto,

Mittlerweile habe ich rausgefunden, dass es in SWT doch einen ersatz für repaint() gibt: _redraw()_ :lol: 
(unglaublich, dass ich solange gebraucht habe, um das rauszufinden...) 
Mit redraw() zwinge ich das Canvas zum neuzeichen - d.h. ich schicke ein neues PaintEvent. So brauch ich dann auch nicht mehr über anonyme PaintListener gehen - aber danke für den Tipp!!!

Mittlerweile funktioniert es so, dass ich ein ein Attribut in meiner Graph Klasse habe, das mit true/false besetzt wird.
In meiner GUI habe ich dann ne Checkbox. Wenn das Häkchen da gesetzt wird, reagiert mein SelectionListener der GUI darauf und setzt dann das Attribut in meiner Graph Klasse auf true. Danach geb ich ein redraw() durch. Dadurch wird meine paint-Methode in der Graph Klasse wieder angesprochen, in der ich dann das Attribut abfrage, und wenn es gesetzt ist, eine Linie hinzuzeichne.

BeispielCode innerhalb meines SelectionListeners:

```
(...)
// zum Verständnis die Deklaration der Variablen:
Graph gr = new Graph(parent, style);
Button bt_check= new Button(parent, SWT.CHECK);
bt_check.addSelectionListener(this);
(...)
public void widgetSelected(SelectionEvent e) {		
	if(e.getSource()==bt_check){
		if(bt_check.getSelection()){
			gr.setLine(true);
			gr.redraw();
 		}
		if(!bt_check.getSelection()){
			gr.setLine(false);
				gr.redraw();
		}
	}
}
```

Dazu der BeispielCode innerhalb meiner Graphklasse:

```
public class Graph extends Canvas implements PaintListener{

private boolean line = false;

  public Graph(Composite parent, int style){
      super(parent, style);
      addPaintListener(this);
  }

  private void paint(PaintEvent e) {
       GC gc = e.gc;
       gc.drawString("Hello World", 50,50);
       
       //hier pruefe ich nun, ob die Linie gezeichnet werden soll, oder nicht.
       if(line){
          gc.drawLine(0,0,100,100);
       }

       gc.dispose();
  }   

  public void setLine(boolean flag){
     this.line=flag;
  }
  
  public void paintControl(PaintEvent e) {
    paint(e);
  }
   
}
```

-------------------------------------



			
				byto hat gesagt.:
			
		

> PS: gc.dispose() ist unnötig, weil Du den GC nicht selbst erzeugst.


Ich hab halt mal gelesen, dass man gc.dispose() stets durchführen soll, da das SystemRessourcen belegt, die erst nach dispose() wieder freigegeben werden...


----------



## byte (11. Apr 2006)

Ah gut zu wissen mit dem redraw(). Brauch ich vielleicht auch bald. 

Wegen dem dispose(): Du musst nur die Komponenten disposen, die Du auch explizit erzeugt hast. Also wenn Du z.b. schreibst GC gc = new GC(), dann musst Du auch irgendwann gc.dispose() machen. Aber in Deinem Fall erzeugst Du das GC ja nicht sondern holst es Dir über e.gc, dann musst Du es auch nicht disposen.


----------

