Newsgroup: it.comp.java
Titolo: Oggetto Graphics, Canvas e metodo Paint

Salve a tutti,
  avrei da porvi un problema che mi è capitato recentemente nello sviluppo
di una piccola applicazione Java.
Ho la necessità di sviluppare una piccola applicazione Java che effettui
degli effetti grafici su video senza interagire minimamente con l'utente,
pertanto l'applicazione non deve contenere JButton o altri tipi di
controlli; semplicemente deve partire, fare il suo lavoro e poi chiudersi.
Per fare ciò, ho preparato un JPanel (naturalmente all'interno di un JFrame)
nel quale ho inserito una Canvas dove disegnare liberamente. Personalmente
ho preferito non utilizzare il metodo Paint per disegnare, ma ho creato un
nuovo metodo nel quale mi sono sbizzarrito. Naturalmente ho creato una
variabile di classe di tipo Graphics che ho inizializzato nel metodo Paint
tramite il metodo getGraphics(), quindi l'ho utilizzata nel mio metodo
personalizzato.
Ora vengo al punto, ho scoperto che alla partenza della piccola applicazione
non viene eseguito il metodo Paint, ed io avevo capito diversamente, ma
soprattutto ho scoperto che viene eseguito tranquillamente alla partenza
aggiungendo un semplice JButton sul pannello. Quello che chiedo è se questo
comportamento è naturale oppure è un bug del runtime che verrà risolto
(forse) in seguito. Mi sembra di aver capito che il metodo Paint viene
richiamato ogni volta che la Canvas viene "danneggiata", pertanto il runtime
si occupa di ridisegnare il tutto, ma io preferirei gestire tutto da solo.
Qualcuno può aiutarmi a capire meglio questo funzionamento ?
Grazie a chiunque voglia interessarsi al mio problema.
Alex.
P.s. utilizzo JDK 1.3. Ciao.

Credo che Swing utilizzi il metodo 
paintComponent() 
anzichč paint() , prova a vedere se il problema č questo...
Se non va, aspetta altre risposte, sono un newbie ;-)
Saluti, P.
--
              Poesia & Entropia                   
 
http://utenti.tripod.it/aiportne/index.htm
 
 



 Qualcuno può aiutarmi a capire meglio questo funzionamento ?
Da quanto ho capito il codice che hai scritto dovrebbe essere qualcosa del
genere:
--- cut here --- cut here ---
import java.awt.* ;
import java.awt.event.* ;
import javax.swing.* ;
class TestCanvas extends JFrame
{
 private Graphics myGraphics ;
 private Canvas theCanvas ;
 TestCanvas()
 {
  super("TestCanvas");
  JPanel thePanel = new JPanel();
  theCanvas = new Canvas();
  theCanvas.setSize(200,200);
  thePanel.add(theCanvas);
  getContentPane().add(thePanel);
  WindowListener w = new WindowAdapter()
  {
   public void windowClosing(WindowEvent e)
   {
    System.exit(0);
   }
  };
  setSize(210,210);
  addWindowListener(w);
  setVisible(true);
 }
 public void paint(Graphics g)
 {
  paintCanvas();
 }
 private void paintCanvas()
 {
  myGraphics = theCanvas.getGraphics();
  myGraphics.drawString("Test", 80, 100 );
  myGraphics.drawOval(50,50,100,100);
 }
 public static void main(String[] args)
 {
  TestCanvas tc = new TestCanvas();
 }
}
--- cut here --- cut here ---
In realtà il metodo paint viene richiamato correttamente (prova ad inserire
un System.out.println(...) per verificarlo), ma il vero problema sta dietro
le quinte e più precisamente nell'ordine in cui vengono chiamati i metodi
paint dei vari componenti ed il metodo proprietario paintCanvas(). La
sequenza di chiamata è la seguente:
1) metodo paint del JFrame (TestCanvas)
2) metodo proprietario paintCanvas (richiamato dal precedente)
3) metodo paint di JPanel
4) metodo paint di Canvas
il problema sta nel fatto che il metodo paint originale di Canvas, chiamato
per ultimo, prevede la semplice cancellazione del canvas, il che fa
scomparire quanto precedentemente disegnato da paintCanvas. Inoltre c'è
anche un problema legato al modo diverso in cui vengono aggiornati i
componenti lightweight (JFrame, JPanel) ed i componenti heavyweight (come il
Canvas.) E' facile rendersene conto giocando un po' con l'applicazione:
alcune volte la finestra viene aggiornata correttamente, ma più spesso ciò
non accade (es. quando viene coperta e poi scoperta o portata a icona e poi
ripristinata)
Il modo giusto di procedere, come specificato sommariamente nella
documentazione del jdk 1.3, è quello di subclassare il metodo paint del
Canvas rimpiazzandolo con un metodo paint proprietario (il che fra l'altro
fa sparire la chiamata poco ortodossa di getGraphics().) Questo accorgimento
viene messo in pratica nel seguente codice che, pur disegnando il canvas
come il precedente, non presenta problemi di aggiornamento:
--- cut here --- cut here ---
import java.awt.* ;
import java.awt.event.* ;
import javax.swing.* ;
class TestCanvas2 extends JFrame
{
 private myCanvas theCanvas ;
 class myCanvas extends Canvas
 {
  public void paint(Graphics g)
  {
   g.drawString("Test", 80, 100 );
   g.drawOval(50,50,100,100);
  }
 }
 TestCanvas2()
 {
  super("TestCanvas2");
  JPanel thePanel = new JPanel();
  theCanvas = new myCanvas();
  theCanvas.setSize(200,200);
  thePanel.add(theCanvas);
  getContentPane().add(thePanel);
  WindowListener w = new WindowAdapter()
  {
   public void windowClosing(WindowEvent e)
   {
    System.exit(0);
   }
  };
  setSize(210,210);
  addWindowListener(w);
  setVisible(true);
 }
 public static void main(String[] args)
 {
  TestCanvas2 tc = new TestCanvas2();
 }
}
--- cut here --- cut here ---
Prova a riadattare il tuo codice sulla falsariga del precedente e non
dovresti più avere i problemi cui accennavi.
Marco.
--
Per scrivermi direttamente elimina
__TOGLIMI__ dall'indirizzo e-mail.

 Qualcuno puņ aiutarmi a capire meglio questo funzionamento ?
Beh, prova a guardare questo esempio che credo faccia piu` o meno quello
che dici..
import java.awt.*;
import javax.swing.*;
public class MyApp extends JFrame implements Runnable {
 private Thread selfThread;
 private int x, y;
 private final static int SIZE=100;
 public MyApp() {
  selfThread=new Thread(this);
  selfThread.start();
 }
 public void paint(Graphics g) {
  super.paint(g);
  g.setColor(Color.white);
  g.fillRect(0, 0, getWidth(), getHeight());
  g.setColor(Color.red);
  g.fillOval(x, y, 16, 16);
 }
 public void run() {
  for (int i=0; i<30; i++) {
   x=(int)(Math.random()*SIZE);
   y=(int)(Math.random()*SIZE);
   repaint();
   try {
    Thread.sleep(250);
   } catch (InterruptedException ex) { }
  }
  dispose();
  System.exit(0);
 }
 public static void main(String args[]) {
  MyApp f = new MyApp();
  f.setSize(SIZE, SIZE);
  f.setVisible(true);
 }
}

Bene,
innanzi tutto vorrei farvi tanti auguri di un felice anno nuovo a tutti
quanti e poi vorrei ringraziarvi per le informazioni che mi avete dato. Dopo
un'attenta analisi ho cambiato strada, ora non disegno più su una Canvas ma
disegno direttamente su un JFrame e apparentemente funziona tutto.
Grazie ancora.
Alex.

